Spring多数据源管理方案

Spring多数据源管理方案

基于Spring的AbstractRoutingDataSource实现多数据源

数据库连接配置

yml 复制代码
spring:
  application:
    name: dynamic-source
  datasource:
    datasource1:
      jdbc-url: jdbc:mysql://localhost:3306/cloud-demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
      driver-class-name: com.mysql.cj.jdbc.Driver
      username: root
      password: root
      initialSize: 1
      maxActive: 20
      minIdle: 1
      maxWait: 60000
    datasource2:
      jdbc-url: jdbc:mysql://localhost:3306/foodie_dev?useUnicode=true&characterEncoding=utf-8&useSSL=false
      driver-class-name: com.mysql.cj.jdbc.Driver
      username: root
      password: root
      initialSize: 1
      maxActive: 20
      minIdle: 1
      maxWait: 60000

数据源配置

java 复制代码
@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.datasource1")
    public DataSource dataSource1() {
        // 根据配置 创建数据源实例
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.datasource2")
    public DataSource dataSource2() {
        return DataSourceBuilder.create().build();
    }

}

继承AbstractRoutingDataSource,实现数据源切换逻辑

java 复制代码
@Component
@Primary
public class DynamicDataSource extends AbstractRoutingDataSource {

    public static ThreadLocal<String> dataSourceKey = new ThreadLocal<>();

    @Autowired
    private DataSource dataSource1;

    @Autowired
    private DataSource dataSource2;

    /**
     * 决定使用哪个数据源之前需要调用这个方法来设置
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return dataSourceKey.get();
    }


    @Override
    public void afterPropertiesSet() {
        HashMap<Object, Object> targetDataSource = new HashMap<>();
        targetDataSource.put("W", dataSource1);
        targetDataSource.put("R", dataSource2);

        //设置数据源
        super.setTargetDataSources(targetDataSource);

        //设置默认数据源
        super.setDefaultTargetDataSource(dataSource1);

        super.afterPropertiesSet();

    }
}

在进行数据库操作时,切换到指定的数据源

java 复制代码
@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private AccountMapper accountManager;


    @RequestMapping("/account")
    public String selectAccount() {
        //查询clouded-demo数据库的account表
        DynamicDataSource.dataSourceKey.set("W");
        Account account = accountManager.selectByPrimaryKey(1);
        return account.toString();
    }


    @Autowired
    private BookMapper bookMapper;

    @RequestMapping("/book")
    public String selectBook() {
        //查询foodie_dev数据库的book表
        DynamicDataSource.dataSourceKey.set("R");
        Book book = bookMapper.selectByPrimaryKey(1);
        return book.toString();
    }

}

基于Mybatis实现多数据源

基于Mybatis实现多数据源管理,需要自己给每个数据源分别注册DataSource、SqlSessionFactory、

ataSourceTransactionManager

注册数据源1

java 复制代码
@Configuration
@MapperScan(basePackages = "com.example.common.dao.w", sqlSessionFactoryRef = "wSqlSessionFactory")
public class WDataSourceConfig {


    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.datasource1")
    public DataSource wDataSource() {
        return DataSourceBuilder.create().build();
    }


    @Bean
    @Primary
    public SqlSessionFactory wSqlSessionFactory(@Qualifier ("wDataSource") DataSource wDataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        //指定这个数据源要使用的mapper文件的位置
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mappers/w/*.xml"));
        sqlSessionFactoryBean.setDataSource(wDataSource);
        return sqlSessionFactoryBean.getObject();
    }


    @Bean
    public DataSourceTransactionManager wDataSourceTransactionManager(@Qualifier ("wDataSource") DataSource wDataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(wDataSource);
        return transactionManager;
    }

}

注册数据源2

java 复制代码
@Configuration
@MapperScan(basePackages = "com.example.common.dao.r", sqlSessionFactoryRef = "rSqlSessionFactory")
public class RDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.datasource2")
    public DataSource rDataSource() {
        return DataSourceBuilder.create().build();
    }


    @Bean
    public SqlSessionFactory rSqlSessionFactory(@Qualifier("rDataSource") DataSource rDataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mappers/r/*.xml"));
        sqlSessionFactoryBean.setDataSource(rDataSource);
        return sqlSessionFactoryBean.getObject();
    }


    @Bean
    public DataSourceTransactionManager rDataSourceTransactionManager(@Qualifier("rDataSource") DataSource rDataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(rDataSource);
        return transactionManager;
    }

}

基于Mybatis实现的多数据源管理不需要在进行数据库操作时切换数据源,因为已经给不同的数据源维护了不同的SqlSessionFactory等组件。

使用dynamic-datasource框架

多数据源下的事务处理

在多数据源下,事务的处理成为了一个问题。因为可能需要对不同的库进行操作,那么这个时候就需要考虑事务问题了。如果一个业务中对两个库进行了操作,那么对这两个库的操作必须要同时失败或者同时成功。

相关推荐
考虑考虑3 小时前
docker compose V2版本新属性
运维·后端·自动化运维
mldong3 小时前
一个 App,十三套后端:手机审批端 uni-jeeflow-app 开源了
java·架构
tqs_123454 小时前
MySQL RR隔离级别死锁|Gap间隙锁、临键锁,订单并发范围查询死锁根因方案
java
逆境不可逃5 小时前
Pi Agent 学习笔记:多个工具怎样并行执行
java
GreenTea5 小时前
7000 万 QPS、500 PB:OpenAI 如何用一个 Python 存储平台撑住 10 亿用户
后端·架构
Flynt5 小时前
Java 27 升级实测:默认值动得比新特性多,有个老参数会让 JVM 直接起不来
java·jvm·后端
Bs_MoneyMagnet5 小时前
基于springboot+vue的个人健康管理系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·vue3·springboot3·计算机毕业设计
GreenTea6 小时前
OpenAI Agents API 上手实测:一次调用把整个 agent loop 甩给 OpenAI
前端·后端·算法
星云API技术支持6 小时前
企业微信二次开发:群权限设置、成员管理与群资料维护的接口组合实践
java·前端·企业微信
niucloud-admin6 小时前
JAVA V6 多商户商城 开发文档——job 计划任务开发
java·python·github