# 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) 注解来控制事务管理器, 与该通知类的加载顺序 , 需要让通知类 , 先加载 , 来判定使用哪个数据源 .(由于事务处理器涉及到数据源,所以必须在触发事务时确定好数据源)