# mysql_demo **Repository Path**: lqwcode/mysql_demo ## Basic Information - **Project Name**: mysql_demo - **Description**: mysql主从复制以及sql优化的案例 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2020-07-09 - **Last Updated**: 2021-01-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 性能优化 - 分页 优化SQL: ```sql select * from operation_log limit 3000000 , 10; ``` 将上述SQL优化为: ```sql select * from operation_log t , (select id from operation_log order by id limit 3000000,10) b where t.id = b.id ; ``` 案例优化代码 ```xml ``` ### 性能优化 - 索引 分页查询时,对需要查询的条件字段加上索引,此时为了保证索引不失效(满足复合索引的最左原则),需要加入多个索引 ```sql CREATE INDEX idx_optlog_method_return_cost ON operation_log(operate_method,return_class,cost_time); CREATE INDEX idx_optlog_return_cost ON operation_log(return_class,cost_time); CREATE INDEX idx_optlog_cost ON operation_log(cost_time); ``` ### 性能优化 - 读写分离 master复制写操作,slave复制读操作,从而减少master的压力 db.properties ```properties jdbc.write.driver=com.mysql.jdbc.Driver jdbc.write.url=jdbc:mysql://192.168.142.128:3306/mysql_demo jdbc.write.username=root jdbc.write.password=itcast jdbc.read.driver=com.mysql.jdbc.Driver jdbc.read.url=jdbc:mysql://192.168.142.129:3306/mysql_demo jdbc.read.username=root jdbc.read.password=itcast ``` applicationContext-datasource.xml ```xml ``` ChooseDataSource ```java public class ChooseDataSource extends AbstractRoutingDataSource { public static Map> METHOD_TYPE_MAP = new HashMap>(); /** * 实现父类中的抽象方法,获取数据源名称 * @return */ protected Object determineCurrentLookupKey() { return DataSourceHandler.getDataSource(); } // 设置方法名前缀对应的数据源 public void setMethodType(Map map) { for (String key : map.keySet()) { List v = new ArrayList(); String[] types = map.get(key).split(","); for (String type : types) { if (!StringUtils.isEmpty(type)) { v.add(type); } } METHOD_TYPE_MAP.put(key, v); } System.out.println("METHOD_TYPE_MAP : "+METHOD_TYPE_MAP); } } ``` DataSourceHandler ```java public class DataSourceHandler { // 数据源名称 public static final ThreadLocal holder = new ThreadLocal(); /** * 在项目启动的时候将配置的读、写数据源加到holder中 */ public static void putDataSource(String datasource) { holder.set(datasource); } /** * 从holer中获取数据源字符串 */ public static String getDataSource() { return holder.get(); } } ``` DataSourceAspect ```java @Aspect @Component @Order(-9999) @EnableAspectJAutoProxy(proxyTargetClass = true) public class DataSourceAspect { protected Logger logger = LoggerFactory.getLogger(this.getClass()); /** * 配置前置通知,使用在方法aspect()上注册的切入点 */ @Before("execution(* cn.itcast.service.*.*(..))") @Order(-9999) public void before(JoinPoint point) { String className = point.getTarget().getClass().getName(); String method = point.getSignature().getName(); logger.info(className + "." + method + "(" + Arrays.asList(point.getArgs())+ ")"); try { for (String key : ChooseDataSource.METHOD_TYPE_MAP.keySet()) { for (String type : ChooseDataSource.METHOD_TYPE_MAP.get(key)) { if (method.startsWith(type)) { System.out.println("key : " + key); DataSourceHandler.putDataSource(key); break; } } } } catch (Exception e) { e.printStackTrace(); } } } ``` 通过 @Order(-9999) 注解来控制事务管理器, 与该通知类的加载顺序 , 需要让通知类 , 先加载 , 来判定使用哪个数据源 .(由于事务处理器涉及到数据源,所以必须在触发事务时确定好数据源)