1.自定义数据源路由
定义自己的路由,继承AbstractRoutingDataSource类
public class MyRoutingDataSource extends AbstractRoutingDataSource {
private static final Logger LOG = LoggerFactory.getLogger(Logger.class);
public final static String MASTER="master";
public final static String SLAVE="slave";
/*保存系统中存在的数据源标识符,然后通过该标识符定位到实际的数据源实体*/
private static final ThreadLocal<String> DB_HOLDER=new ThreadLocal<>();
public static void master(){
DB_HOLDER.set(MASTER);
LOG.info("切换到主库......");
}
public static void slave(){
DB_HOLDER.set(SLAVE);
LOG.info("切换到从库......");
}
@Override
protected Object determineCurrentLookupKey() {
return DB_HOLDER.get();
}
}
定义数据库连接配置yml文件
spring:
datasource:
master:
username: root
password: 123456@cP
jdbc-url: jdbc:mysql://127.0.0.1:3306/test_db01?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
slave:
username: root
password: 123456@cP
jdbc-url: jdbc:mysql://127.0.0.1:3306/test_db01?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
2.配置数据源
配置数据源DataSourceConfig
@Configuration
public class DataSourceConfig {
/**
* @Description 主数据库配置
* @date 2020/4/17 18:11
* @author cp
*/
@Bean
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource(){
return create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.slave")
public DataSource slaveDataSource(){
return create().build();
}
/**
* @Description 自定义数据源,内部持有主库和从库的数据源
* 通过某种机制让应用程序在进行数据读写时,按业务情况走主库还是从库
* @method myRoutingDataSource
* @param masterDataSource, slaveDataSource
* @return javax.sql.DataSource
* @date 2020/4/17 19:21
* @author cp
*/
@Bean
public DataSource myRoutingDataSource(
@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slaveDataSource") DataSource slaveDataSource
){
Map<Object,Object> targetDataSource=new HashMap<>();
targetDataSource.put(MyRoutingDataSource.MASTER,masterDataSource);
targetDataSource.put(MyRoutingDataSource.SLAVE,slaveDataSource);
MyRoutingDataSource myRoutingDataSource=new MyRoutingDataSource();
//通过AOP织入的方法,自动选择主/从库
myRoutingDataSource.setTargetDataSources(targetDataSource);
//未在AOP织入的方法内,默认走主库
myRoutingDataSource.setDefaultTargetDataSource(masterDataSource);
return myRoutingDataSource;
}
}
3.aop配置
实现自己的读写分离规则
@Aspect
@Component
public class DataSourceAop {
/**
* @Description 主库的切点,通过注解Master的方法或者名为insert、update、add等开头的操作性方法,走主库
* @method masterPointcut
* @param
* @return void
* @date 2020/4/17 18:27
* @author cp
*/
@Pointcut("@annotation(com.cpo.annotation.Master)" +
"|| execution(* com.cpo.service..*.insert*(..))" +
"|| execution(* com.cpo.service..*.save*(..))" +
"|| execution(* com.cpo.service..*.add*(..))" +
"|| execution(* com.cpo.service..*.update*(..))" +
"|| execution(* com.cpo.service..*.edit*(..))" +
"|| execution(* com.cpo.service..*.delete*(..))" +
"|| execution(* com.cpo.service..*.del*(..))" +
"|| execution(* com.cpo.service..*.remove*(..))")
public void masterPointcut(){
}
/**
* @Description 主库的切点,通过注解Slave的方法或者名为select、find、get等开头的操作性方法,走从库
* @method slavePointcut
* @param
* @return void
* @date 2020/4/17 18:27
* @author cp
*/
@Pointcut("@annotation(com.cpo.annotation.Slave)" +
"|| execution(* com.cpo.service..*.select*(..))" +
"|| execution(* com.cpo.service..*.find*(..))" +
"|| execution(* com.cpo.service..*.get*(..))" +
"|| execution(* com.cpo.service..*.query*(..))")
public void slavePointcut(){
}
/**
* @Description 织入位置 前置通知,在方法执行之前
* @method master
* @return void
* @date 2020/4/17 19:08
* @author cp
*/
@Before("masterPointcut()")
public void master(){
MyRoutingDataSource.master();
}
/**
* @Description 织入位置 前置通知,在方法执行之前
* @method slave
* @return void
* @date 2020/4/17 19:08
* @author cp
*/
@Before("slavePointcut()")
public void slave(){
MyRoutingDataSource.slave();
}
}