spring boot + mybatis 实现不确定多少数据源的情况下,动态切换数据源
spring boot + mybatis 实现不确定多少数据源的情况下,动态切换数据源
建议最好是自己能独立集成mybatis,再参照本章
场景举例: 例如每个用户都有一个独立的数据库。
数据库信息介绍:采用的数据库是mysql,一共有两个库,一个库存的是用户信息,包括用户账号密码,用户的业务库账号密码url。一个是用户的业务库
mk_user表
mk_othermessage表
下面是代码部分
这里用的连接池是 druid
1.创建主数据源(mk_user库)
spring.datasource.druid.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/mk_user
spring.datasource.druid.username=root
spring.datasource.druid.password=1234
@Bean
@ConfigurationProperties(prefix = "spring.datasource.druid")
public DataSource dataSource(){
return new DruidDataSource();
}
2.创建DataSourceContextHolder类用于存数据源的key,因为所有数据源都存在一个map容器中
public class DataSourceContextHolder {
private static final ThreadLocal<String> threadLocal = new ThreadLocal();
public static void setValue(String data){
threadLocal.set(data);
}
public static String getValue(){
return threadLocal.get();
}
}
3.创建DynamicDataSource类,AbstractRoutingDataSource类是spring boot 用来支持多数据源的类,determineCurrentLookupKey方法返回一个key
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getValue();
}
}
4.创建动态数据源bean并指定默认数据源,这里默认数据源为 mk_user,注意targetDatsource要给一个不是null值得容器,源码中对此处做了判断,不给的话会报错
@Bean
@Primary
public DynamicDataSource dynamicDataSource(){
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(dataSource());
Map<Object,Object> dataSourceMap = new HashMap();
dynamicDataSource.setTargetDataSources(dataSourceMap);
return dynamicDataSource;
}
5.项目启动的完成后向动态数据源的容器中添加所有的数据源这里数据源的key为username,实现CommandLineRunner接口中的run方法会在启动完成后自动执行
@Component
public class InitTargetDataSources implements CommandLineRunner{
@Autowired
UserService userService;
@Autowired
DynamicDataSource dynamicDataSource;
@Override
public void run(String... args) throws Exception {
List<User> userList = userService.findAll();
Map<Object,Object> dataSourceMap = userList.stream().collect(Collectors.toMap(
user -> user.getUsername(),user ->{
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
druidDataSource.setUrl(user.getDatasourceUrl());
druidDataSource.setUsername(user.getDatasourceUsername());
druidDataSource.setPassword(user.getDatasourcePassword());
return druidDataSource;
}
));
dynamicDataSource.setTargetDataSources(dataSourceMap);
dynamicDataSource.afterPropertiesSet();
}
}
以上动态数据源就基本完成了,现在还差当客户端请求过来的时候我们指定该用那个数据源,这要跟场景而定,如果采用的是seesion验证那么这个用户就在session中取然后设定key,如果是token验证就应该在过滤器中设定key,因为这是个demo所以没有加用户验证
所以这里就用切面手动切换。下面是切面代码,这里设定的是 “dev” 即用户名
@Component
@Aspect
public class DataSourceAspect {
@Pointcut("execution(* com.demo.controller.OtherMessageController.*(..))")
public void pointcut(){
}
@Before(value = "pointcut()")
public void dataSourceSwitch(JoinPoint joinPoint){
DataSourceContextHolder.setValue("dev");
}
}
测试: