1.数据源
#其它配置
spring:
#MySQL数据库
datasource:
main:
jdbc-url: jdbc:mysql:///zcfx_main?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: trkj.2020
slave1:
jdbc-url: jdbc:mysql:///zcfx_a?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: trkj.2020
slave2:
jdbc-url: jdbc:mysql:///zcfx_b?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: trkj.2020
2.创建数据源枚举,方便运行时切换
public enum DatabaseType {
DATASOURCE_A,DATASOURCE_B,DATASOURCE_MAIN
}
3.设置数据源切换类
public class DatabaseContextHolder {
private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();
public static void setDatabaseType(DatabaseType type) {
contextHolder.set(type);
}
public static DatabaseType getDatabaseType() {
return contextHolder.get();
}
}
4.动态数据源继承AbstractRoutingDataSource类
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DatabaseContextHolder.getDatabaseType();
}
}
5.数据源配置
/** 定义数据源配置-主库 */
@Configuration
@MapperScan(basePackages="bw.zcfx.svc.module", sqlSessionFactoryRef="mainSqlSessionFactory")
public class DataSourceMainConfig
{
@Primary //表示这个数据源是默认数据源
@Bean("mainDataSource") //将这个对象放入Spring容器中
@ConfigurationProperties(prefix="spring.datasource.main") //读取配置文件中的参数,并指定参数名的前缀
public DataSource getDataSource()
{
return DataSourceBuilder.create().build();
}
@Bean("datasource1")
@ConfigurationProperties(prefix = "spring.datasource.slave1")
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
}
@Bean("datasource2")
@ConfigurationProperties(prefix = "spring.datasource.slave2")
public DataSource dataSource2() {
return DataSourceBuilder.create().build();
}
//配置多数据源,使用ThreadLocal对对应的线程保存不用的类型,根据类型获取不同的数据源
@Bean("datasource")
@Primary
public DynamicDataSource dataSource(@Qualifier("datasource1") DataSource dataSource1,
@Qualifier("datasource2") DataSource dataSource2,@Qualifier("mainDataSource") DataSource mainDataSource) {
Map<Object, Object> targetDataSource = new HashMap<>();
targetDataSource.put(DatabaseType.DATASOURCE_A, dataSource1);
targetDataSource.put(DatabaseType.DATASOURCE_B, dataSource2);
targetDataSource.put(DatabaseType.DATASOURCE_MAIN, mainDataSource);
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setTargetDataSources(targetDataSource);
dataSource.setDefaultTargetDataSource(mainDataSource);
return dataSource;
}
@Primary
@Bean("mainSqlSessionFactory")
public SqlSessionFactory mainSqlSessionFactory(@Qualifier("datasource") DataSource datasource) throws Exception
{
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(datasource);
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
configuration.setJdbcTypeForNull(JdbcType.NULL);
sqlSessionFactory.setConfiguration(configuration);
sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/**/*.xml"));
sqlSessionFactory.setPlugins(new Interceptor[]{
new PaginationInterceptor(),
new PerformanceInterceptor(),
new OptimisticLockerInterceptor()
});
return sqlSessionFactory.getObject();
}
@Primary
@Bean("mainSqlSessionTemplate")
public SqlSessionTemplate mainSqlSessionTemplate(@Qualifier("mainSqlSessionFactory") SqlSessionFactory sessionfactory)
{
return new SqlSessionTemplate(sessionfactory);
}
@Bean("mainTransactionManager")
@Primary
public PlatformTransactionManager mainTransactionManager(@Qualifier("mainDataSource")DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
6.调用持久层时,选择数据库
DatabaseContextHolder.setDatabaseType(DatabaseType.DATASOURCE_A);
我是写了个工具类,获取配置自动设置
public class MysqlUtil {
public static void selectMysql() {
String mYSQL_NUM = AppBuffer.MYSQL_NUM;
if("A".equals(mYSQL_NUM)) {
DatabaseContextHolder.setDatabaseType(DatabaseType.DATASOURCE_A);
}
if("B".equals(mYSQL_NUM)) {
DatabaseContextHolder.setDatabaseType(DatabaseType.DATASOURCE_B);
}
}
public static void setMysql(DatabaseType databaseType) {
DatabaseContextHolder.setDatabaseType(databaseType);
}
}
7.1 测试方法1
注:动态设置只对当前调用线程起作用,如果同一个线程想再次调用其他数据库,建议每次调用设置数据源,返回时切换回默认数据源
/** 查询所有的配置(包括不可见的) */
public List<SysConfigPO> getAll()
{
MysqlUtil.selectMysql();
List<SysConfigPO> selectList = baseMapper.selectList(null);
MysqlUtil.setMysql(DatabaseType.DATASOURCE_MAIN);
return selectList;
}
@GetMapping("/getSlave")
@ApiOperation(value="查询从库", notes="")
public CommonResponse getSlave()
{
CommonResponse resp = new CommonResponse<SysUserVO>();
List<SysConfigPO> list = sysConfigService.getAll();
resp.addData("data1",list);
List<SysConfigPO> list2 = sysConfigService.lambdaQuery().list();
resp.addData("data2",list2);
return resp;
}

7.2 测试方法2
/** 查询所有的配置(包括不可见的) */
public List<SysConfigPO> getAll()
{
MysqlUtil.selectMysql();
List<SysConfigPO> selectList = baseMapper.selectList(null);
// MysqlUtil.setMysql(DatabaseType.DATASOURCE_MAIN);
return selectList;
}

看两次测试结果,第一次调用没切换回默认库,线程向下进行第二次调用还是使用从库
8.为了减小代码侵入可以使用AOP切入service方法
8.1.新增切入注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value() default "";
}
8.2切入程序
/**
* 切换数据源,切面处理类
*
*/
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("@annotation(bw.zcfx.svc.common.annotation.DataSource)")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MysqlUtil.selectMysql();
// 执行方法
Object result = point.proceed();
MysqlUtil.setMysql(DatabaseType.DATASOURCE_MAIN);
return result;
}
}
8.3测试方法
@DataSource
public List<SysConfigPO> getAll()
{
return baseMapper.selectList(null);
}

9.数据库表



3068

被折叠的 条评论
为什么被折叠?



