SpringBoot中使用动态数据源和多数据源配置

1、使用Spring提供的AbstractRoutingDataSource

这种方式的核心是使用Spring提供的AbstractRoutingDataSource抽象类,注入多个数据源。

@Component
@Primary // 将该Bean设置为主要注入Bean
public class DynamicDataSource extends AbstractRoutingDataSource {
    // 当前使用的数据源标识
    public static ThreadLocal<String> name=new ThreadLocal<>();
    // 写库
    @Autowired
    DataSource dataSource1;
    // 读库
    @Autowired
    DataSource dataSource2;
    // 返回当前数据源标识
    @Override
    protected Object determineCurrentLookupKey() {
        return name.get();
    }
    @Override
    public void afterPropertiesSet() {
        // 为targetDataSources初始化所有数据源
        Map<Object, Object> targetDataSources=new HashMap<>();
        targetDataSources.put("W",dataSource1);
        targetDataSources.put("R",dataSource2);
        super.setTargetDataSources(targetDataSources);
        // 为defaultTargetDataSource 设置默认的数据源
        super.setDefaultTargetDataSource(dataSource1);
        super.afterPropertiesSet();
    }
}

将自己实现的DynamicDataSource注册成为默认的DataSource实例后,只需要在每次使用 DataSource时,提前改变一下其中的name标识,就可以快速切换数据源。

@Component
@Aspect
public class DynamicDataSourceAspect implements Ordered {
    // 在每个访问数据库的方法执行前执行。
    @Before("within(com.tuling.dynamic.datasource.service.impl.*) &&
            @annotation(wr)")
    public void before(JoinPoint point, WR wr){
        String name = wr.value();
        DynamicDataSource.name.set(name);
        System.out.println(name);
    }
    @Override
    public int getOrder() {
        return 0;
    }
}
@Service
public class FriendImplService implements FriendService {
    @Autowired
    FriendMapper friendMapper;

    @Override
    @WR("R")        // 库2
    public List<Friend> list() {
        //        DynamicDataSource.name.set("R");
        return friendMapper.list();
    }
    
    @Override
    @WR("W")        // 库1
    public void save(Friend friend) {
        //        DynamicDataSource.name.set("W");
        friendMapper.save(friend);
    }

}

2、使用MyBatis注册多个SqlSessionFactory

如果使用MyBatis框架,要注册多个数据源的话,就需要将MyBatis底层的DataSource、 SqlSessionFactory、DataSourceTransactionManager这些核心对象一并进行手动注册。例如:

@Configuration
@MapperScan(basePackages = "com.lhj.datasource.dynamic.mybatis.mapper.r",
            sqlSessionFactoryRef="rSqlSessionFactory")
public class RMyBatisConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.datasource2")
    public DataSource dataSource2() {
        // 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSource
        return DruidDataSourceBuilder.create().build();
    }
    @Bean
    @Primary
    public SqlSessionFactory rSqlSessionFactory()
    throws Exception {
        final SqlSessionFactoryBean sessionFactory = new
        SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource2());
        // 指定主库对应的mapper.xml文件
        /*sessionFactory.setMapperLocations(new
PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/r/*.xml"));*/
        return sessionFactory.getObject();
    }
    @Bean
    public DataSourceTransactionManager rTransactionManager(){
        DataSourceTransactionManager dataSourceTransactionManager = new
        DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource2());
        return dataSourceTransactionManager;
    }
    @Bean
    public TransactionTemplate rTransactionTemplate(){
        return new TransactionTemplate(rTransactionManager());
    }
}
@Service
public class FriendImplService implements FriendService {

    @Autowired
    private RFriendMapper rFriendMapper;
    @Autowired
    private WFriendMapper wFriendMapper;

    // 读-- 读库
    @Override
    public List<Friend> list() {
        return rFriendMapper.list();
    }
    // 保存-- 写库
    @Override
    public void save(Friend friend) {
        wFriendMapper.save(friend);
    }

    // 保存-- 写库
    @Override
    public void saveW(Friend friend) {
        friend.setName("loulan");
        wFriendMapper.save(friend);
    }

    // 保存-- 读库
    @Override
    public void saveR(Friend friend) {
        friend.setName("loulan");
        rFriendMapper.save(friend);
    }
}

这样就完成了读库的注册。而读库与写库之间,就可以通过指定不同的Mapper和XML文件的地址来 进行区分。

3、使用dynamic-datasource框架

dynamic-datasource是MyBaits-plus作者设计的一个多数据源开源方案。使用这个框架需要引入对应 的pom依赖

<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  <version>3.5.0</version>
</dependency>

这样就可以在SpringBoot的配置文件中直接配置多个数据源。

spring:
  datasource:
    dynamic:
      #设置默认的数据源或者数据源组,默认值即为master
      primary: master
      #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      strict: false
      datasource:
        master:
          url: jdbc:mysql://127.0.0.1:3306/datasource1?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=false
          username: root
          password: root
          initial-size: 1
          min-idle: 1
          max-active: 20
          test-on-borrow: true
          driver-class-name: com.mysql.cj.jdbc.Driver
        slave_1:
          url: jdbc:mysql://127.0.0.1:3306/datasource2?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=false
          username: root
          password: root
          initial-size: 1
          min-idle: 1
          max-active: 20
          test-on-borrow: true
          driver-class-name: com.mysql.cj.jdbc.Driver

这样就配置完成了master和slave_1两个数据库。 接下来在使用时,只要在对应的方法或者类上添加@DS注解即可。例如

@Service
public class FriendImplService implements FriendService {

    @Autowired
    FriendMapper friendMapper;

    @Override
    @DS("slave_1")  // 从库, 如果按照下划线命名方式配置多个  , 可以指定前缀即可(组名)
    public List<Friend> list() {
        return friendMapper.list();
    }

    @Override
    @DS("master")
    public void save(Friend friend) {
        friendMapper.save(friend);
    }


    //    @DS("master")
    //    @DSTransactional
    //    public void saveAll(){
    //        // 执行多数据源的操作
    //    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值