日常开发中大家大家都会遇到多数据源切换,下面写一下我的配置情况,供大家参考。
数据源支持 Oracle、Mysql、Sqlserver、presto等
下面使用两个数据库来进行配置 分为A库和B库
下面是搭建步骤
1、先在application.properties配置两个数据源
数据库连接池使用的是Hikari
A库是Oracle B库是mysql
#mybatis
mybatis.mapper-locations= classpath*:mapper/*/*/*.xml
mybatis.typeAliasesPackage= com.pojo
mybatis.configuration.call-setters-on-nulls=true
#A 库
multiple.datasource.A.type=com.zaxxer.hikari.HikariDataSource
multiple.datasource.A.driver-class-name=oracle.jdbc.OracleDriver
multiple.datasource.A.jdbc-url=
multiple.datasource.A.username=
multiple.datasource.A.password=
# 最小空闲连接数量
multiple.datasource.A.minimum-idle=5
# 连接池最大连接数,默认是10
multiple.datasource.A.maximum-pool-size=10
# 此属性控制从池返回的连接的默认自动提mes,默认值:true
multiple.datasource.A.auto-commit=true
# 空闲连接存活最大时间,默认60000mes0分钟)
multiple.datasource.A.idle-timeout=30000
# 连接池名称
multiple.datasource.A.pool-name=AHikariCP
# 此属性控制池中连接的最长生命周期,默认1800000即30分钟
multiple.datasource.A.max-lifetime=1800000
# 数据库连接超时时间,默认30秒,即3mes0
multiple.datasource.A.connection-timeout=30000
multiple.datasource.A.connection-test-query=SELECT 1 FROM DUAL
#B数据库
multiple.datasource.B.type= com.zaxxer.hikari.HikariDataSource
multiple.datasource.B.driver-class-name=com.mysql.cj.jdbc.Driver
multiple.datasource.B.jdbc-url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
multiple.datasource.B.username=
multiple.datasource.B.password=
# 最小空闲连接数量
multiple.datasource.B.minimum-idle=5
# 连接池最大连接数,默认是10
multiple.datasource.B.maximum-pool-size=10
# 此属性控制从池返回的连接的默认自动提交行为,默认值:true
multiple.datasource.B.auto-commit=true
# 空闲连接存活最大时间,默认600000(10分钟)
multiple.datasource.B.idle-timeout=30000
# 连接池名称
multiple.datasource.B.pool-name=BHikariCP
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
multiple.datasource.B.max-lifetime=1800000
# 数据库连接超时时间,默认30秒,即30000
multiple.datasource.B.connection-timeout=30000
multiple.datasource.B.connection-test-query=SELECT 1 FROM DUAL
2、编写自定义数据源注解 后面通过Spring AOP进行切换
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TargetDataSource {
//默认A库
DataSourceKey dataSourceKey() default DataSourceKey.A;
}
3、配置多数据源
public enum DataSourceKey {
A,
B
}
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<DataSourceKey> currentDatesource = new ThreadLocal<>();
/**
* 清除当前数据源
*/
public static void clear() {
currentDatesource.remove();
}
/**
* 获取当前使用的数据源
*
* @return 当前使用数据源的ID
*/
public static DataSourceKey get() {
return currentDatesource.get();
}
/**
* 设置当前使用的数据源
*
* @param value 需要设置的数据源ID
*/
public static void set(DataSourceKey value) {
currentDatesource.set(value);
}
/**
* 设置从A库读取数据
*/
public static void setA() {
DynamicDataSourceContextHolder.set(DataSourceKey.A);
}
/**
* 设置从B库读取数据
*/
public static void setB() {
DynamicDataSourceContextHolder.set(DataSourceKey.B);
}
}
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
private static final Logger LOG = LoggerFactory.getLogger(DynamicRoutingDataSource.class);
@Override
protected Object determineCurrentLookupKey() {
LOG.info("当前数据源:"+ DynamicDataSourceContextHolder.get());
return DynamicDataSourceContextHolder.get();
}
}
@Configuration
public class DynamicDataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "multiple.datasource.A")
public DataSource dbA() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "multiple.datasource.B")
public DataSource dbB() {
return DataSourceBuilder.create().build();
}
/**
* 核心动态数据源
*
* @return 数据源实例
*/
@Bean
public DataSource dynamicDataSource() {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.setDefaultTargetDataSource(dbA());
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put(DataSourceKey.A, dbA());
dataSourceMap.put(DataSourceKey.B, dbB());
dataSource.setTargetDataSources(dataSourceMap);
return dataSource;
}
@Value("${mybatis.mapper-locations}")
private String mapperLocation;
@Value("${mybatis.typeAliasesPackage}")
private String typeAliasesPackage;
@Value("${mybatis.configuration.call-setters-on-nulls}")
private boolean callSettersOnNulls;
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource());
//此处设置为了解决找不到mapper文件的问题
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(mapperLocation);
sqlSessionFactoryBean.setMapperLocations(resources);
//POJO
sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage);
//此处设置为了解决 查询数据为null不显示该字段 true显示 false不显示
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setCallSettersOnNulls(callSettersOnNulls);
sqlSessionFactoryBean.setConfiguration(configuration);
return sqlSessionFactoryBean.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate() throws Exception {
return new SqlSessionTemplate(sqlSessionFactory());
}
/**
* 事务管理
*
* @return 事务管理实例
*/
@Bean
public PlatformTransactionManager platformTransactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}
4、配置切面拦截注解进行数据库切换
@Aspect
@Order(-1)
@Component
public class DynamicDataSourceAspect {
private static final Logger LOG = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
/**
* 执行方法前更换数据源
*
* @param joinPoint 切点
* @param targetDataSource 动态数据源
*/
@Before("@annotation(targetDataSource)")
public void doBefore(JoinPoint joinPoint, TargetDataSource targetDataSource) {
DataSourceKey dataSourceKey = targetDataSource.dataSourceKey();
DynamicDataSourceContextHolder.set(dataSourceKey);
}
/**
* 执行方法后清除数据源设置
*
* @param joinPoint 切点
* @param targetDataSource 动态数据源
*/
@After("@annotation(targetDataSource)")
public void doAfter(JoinPoint joinPoint, TargetDataSource targetDataSource) {
LOG.info(String.format("当前数据源 %s 执行清理方法", targetDataSource.dataSourceKey()));
DynamicDataSourceContextHolder.clear();
}
}
5、在Mapper文件中指定数据源
@Mapper
public interface EquipmentCheckMapper {
/**
* A库读取数据
* @param
* @return
*/
@TargetDataSource(dataSourceKey = DataSourceKey.A)
List<Student> getA();
/**
* B库读取数据
* @param
* @return
*/
@TargetDataSource(dataSourceKey = DataSourceKey.B)
List<Student> getB();
6、启动类注解也要配置
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableAspectJAutoProxy
至此 多数据的配置工作就完成了