Spring基于AbstractRoutingDataSource实现MySQL多数据源

发布时间:2024年01月24日

目录

多数据源实现

yml配置文件

配置类

业务代码

案例演示


多数据源实现

yml配置文件
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    datasource1:
      url: jdbc:mysql://127.0.0.1:3306/datasource1?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=false
      username: root
      password: 123456
      initial-size: 1
      min-idle: 1
      max-active: 20
      test-on-borrow: true
      driver-class-name: com.mysql.cj.jdbc.Driver
    datasource2:
      url: jdbc:mysql://127.0.0.1:3306/datasource2?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF8&useSSL=false
      username: root
      password: 123456
      initial-size: 1
      min-idle: 1
      max-active: 20
      test-on-borrow: true
      driver-class-name: com.mysql.cj.jdbc.Driver

?创建两个数据库分别为datasource1、datasource2,在两个数据中分别创建一张friend表

配置类

配置两个DataSource的Bean

@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.datasource1")
    public DataSource dataSource1() {
        // 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSource
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.datasource2")
    public DataSource dataSource2() {
        // 底层会自动拿到spring.datasource中的配置, 创建一个DruidDataSource
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    public DataSourceTransactionManager transactionManager1(DynamicDataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }

    @Bean
    public DataSourceTransactionManager transactionManager2(DynamicDataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}
@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();
    }
}

? ? ? ?继承AbstractRoutingDataSource类,定义一个threadlocal线程变量,并将两个数据源自动注入,在重写的afterPropertiesSet方法中(该方法是bean初始化后执行的方法),将两个数据源放入到spring管理的数据源中,通过重写的determineCurrentLookupKey方法返回W或R表示读库或写库。

业务代码
@RestController
@RequestMapping("friend")
@Slf4j
public class FrendController {

    @Autowired
    private FrendService frendService;

    @GetMapping(value = "select")
    public List<Friend> select(){
        return frendService.list();
    }

    @GetMapping(value = "insert")
    public String insert(){
        Friend friend = new Friend();
        friend.setName("张三");
        frendService.save(friend);
        return "success";
    }
}
public interface FrendService  {
    List<Friend> list();

    void save(Friend frend);

}
@Service
public class FrendImplService implements FrendService {

    @Autowired
    FrendMapper frendMapper;


    @Override
//    @WR("R")        // 库2
    public List<Friend> list() {
        DynamicDataSource.name.set("R");
        return frendMapper.list();
    }

    @Override
//    @WR("W")        // 库1
    public void save(Friend frend) {
        DynamicDataSource.name.set("W");
        frendMapper.save(frend);
    }

}

? ? ? ?在具体的实现当中,先通过DynamicDataSource设置需要的操作的数据库。或者可以用注解的方式来实现,注解配置如下:

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface WR {
    String value() default "W";
}
@Component
@Aspect
public class DynamicDataSourceAspect implements Ordered {

    // 前置
    @Before("within(com.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);
    }

}

通过切面的方式,获取到当前方法需要操作的数据库。

案例演示

启动项目后,执行select请求

执行insert请求

查看数据库

发现datasource1有数据,datasource2无数据。

如果上述两种数据库是主从的话,此种方式可以实现主从数据库,主库写入,从库负责读。

文章来源:https://blog.csdn.net/m0_61853556/article/details/135824604
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。