实现思路:继承 AbstractRoutingDataSource 实现动态切换(aop对于主从变量进行切换)根据变量key读取对应的数据源实例 必须覆盖SqlSessionFactory 、SqlSessionTemplate
@Configuration
public class DataSourceConfig {
/**
* 主数据库数据源,存入Spring容器
* 注解@Primary表示主数据源
* @return
*/
@ConfigurationProperties(prefix = "spring.datasource.master")
@Primary
@Bean
public DataSource masterDataSource(){
return DruidDataSourceBuilder.create().build();
}
/**
* 从数据库数据源,存入Spring容器
* @return
*/
@ConfigurationProperties(prefix = "spring.datasource.slave")
@Bean
public DataSource slaveDataSource(){
return DruidDataSourceBuilder.create().build();
}
/**
* 决定最终数据源
* @param masterDataSource
* @param slaveDataSource
* @return
*/
@Bean
public DynamicDataSource targetDataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slaveDataSource") DataSource slaveDataSource){
//存放主从数据源
Map<Object,Object> targetDataSource = new HashMap<>(2);
//主数据源
targetDataSource.put(DBTypeEnum.MASTER, masterDataSource);
//从数据源
targetDataSource.put(DBTypeEnum.SLAVE, slaveDataSource);
//实现动态切换
DynamicDataSource dynamicDataSource = new DynamicDataSource();
//绑定所有数据源
dynamicDataSource.setTargetDataSources(targetDataSource);
//设置默认数据源
dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
return dynamicDataSource;
}
@Bean
public SqlSessionFactory sessionFactory(@Qualifier("targetDataSource") DataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*"));
bean.setDataSource(dynamicDataSource);
return bean.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
}
/***
* 当自定义数据源,用户必须注入,否则事务控制不生效
* @param dataSource
* @return
*/
@Bean
public DataSourceTransactionManager dataSourceTx(@Qualifier("targetDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
---------------------------------------------------------------------------------------------------------------------------------------------------
public class DynamicDataSource extends AbstractRoutingDataSource {
private Logger logger = LoggerFactory.getLogger(DynamicDataSource.class);
@Override
protected Object determineCurrentLookupKey() {
logger.info("使用数据源:"+DynamicDbUtil.get());
return DynamicDbUtil.get();
}
}
---------------------------------------------------------------------------------------------------------------------------------------------------
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DBType {
DBTypeEnum dbType() default DBTypeEnum.MASTER;
}
public enum DBTypeEnum {
/**
* 主数据库
*/
MASTER,
/**
* 从数据库
*/
SLAVE;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------
@Aspect
@Component
public class DataSourceAopAspect {
private Logger logger = LoggerFactory.getLogger(DataSourceAopAspect.class);
@Pointcut("@annotation(com.cn.datasource.annotation.DBType)")
public void dataSourceAopAspect(){
}
/**
* 配置前置通知,切换数据源为从数据库
*/
@Before("dataSourceAopAspect()")
public void readAdvise(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
DBType dbTypeAn = method.getAnnotation(DBType.class);
DBTypeEnum dbType = dbTypeAn.dbType();
//先移除
DynamicDbUtil.remove();
//设置数据源
DynamicDbUtil.set(dbType);
logger.info("切换到数据源:"+DynamicDbUtil.get());
}
}