Skip to content

00. 前言

在实际开发中,即使在微服务盛行的今天,在一个系统中可能会有用到多个数据源(最简单的读写分离),但mybatis默认只有一个数据源,我们想用多个数据源的话,就只能自己去控制数据源,当前采用的是拦截器拦截自定义注解,在执行sql之前切换到具体的数据源,并在执行完之后销毁数据源。

01. 使用方法

1.在application-dev.yml配置数据源

 # 数据源配置
  datasource:
    master:
      # 原框架数据库配置,涉及的到太多,没办法删除
      dbtype: Oracle
      dbname: PDBORCL
      host: 192.168.3.210
      port: 1521
      # 表空间(当数据库为Oracle、达梦DM8、金仓KingbaseES时表空间必须指定,其他数据库为空即可)
      tablespace: JNPF


# 共用配置
      username: JNPF
      password: ENC(Jb1Yv5tBdfWAaJVEUSKsmg==) #密码:JNPF


# 多数据源配置
      jdbcUrl: jdbc:oracle:thin:@//192.168.3.210/pdborcl
      type: com.alibaba.druid.pool.DruidDataSource
      driverClassName: oracle.jdbc.OracleDriver
    slave1:
      dbtype: Oracle
      dbname: PDBORCL
      host: 192.168.3.210
      port: 1521
      # 表空间(当数据库为Oracle、达梦DM8、金仓KingbaseES时表空间必须指定,其他数据库为空即可)
      tablespace: XM_BDCDC_TLW


# 共用配置
      username: XM_BDCDC_TLW
      password: ENC(BtB1Bm3D/zvKdSC6pVXL1Xqbt+j7Qgpm) #XM_BDCDC_TLW


# 多数据源配置
      jdbcUrl: jdbc:oracle:thin:@//192.168.3.210:1521/pdborcl
      type: com.alibaba.druid.pool.DruidDataSource
      driverClassName: oracle.jdbc.OracleDriver
    slave2:
      dbtype: Oracle
      dbname: PDBORCL
      host: 192.168.3.210
      port: 1521
      # 表空间(当数据库为Oracle、达梦DM8、金仓KingbaseES时表空间必须指定,其他数据库为空即可)
      tablespace: XM_BDCDC_WS_TLW


# 共用配置
      username: XM_BDCDC_WS_TLW
      password: ENC(ScfQHDnNLpDNcCPZqbMWikIvBT8ZaF7c) #XM_BDCDC_WS_TLW


# 多数据源配置
      jdbcUrl: jdbc:oracle:thin:@//192.168.3.210:1521/pdborcl
      type: com.alibaba.druid.pool.DruidDataSource
      driverClassName: oracle.jdbc.OracleDriver
    slave3:
      dbtype: Oracle
      dbname: PDBORCL
      host: 192.168.3.210
      port: 1521
      # 表空间(当数据库为Oracle、达梦DM8、金仓KingbaseES时表空间必须指定,其他数据库为空即可)
      tablespace: XM_BDCDCCG_TLW


# 共用配置
      username: XM_BDCDCCG_TLW
      password: ENC(rJZED+J5v6KaLuwnyOhvcCfN2vUR4edw) #XM_BDCDCCG_TLW


# 多数据源配置
      jdbcUrl: jdbc:oracle:thin:@//192.168.3.210:1521/pdborcl
      type: com.alibaba.druid.pool.DruidDataSource
      driverClassName: oracle.jdbc.OracleDriver
    slave4:
    slave5:

2.在DynamicDataSourceConfig中从yml文件读取多个数据源进行解析,生成多数据源进行存储,目前默认配置5个,如果数据源较多,采用配置枚举 多数据源配置1

  1. 使用**@DbChoose**切换数据源。

@DbChoose可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解

注解结果
没有@DbChoose默认数据源
@DbChoose("dsName")dsName为具体某个库的名称
@Service
@DbChoose("slave1")
public class UserServiceImpl implements UserService {


@Autowired
  private JdbcTemplate jdbcTemplate;


public List selectAll() {
    return  jdbcTemplate.queryForList("select * from user");
  }


@Override
  @DbChoose("slave2")
  public List selectByCondition() {
    return  jdbcTemplate.queryForList("select * from user where age >10");
  }
}

02. 事务

基础知识

问:使用了事务如@Transational 无法切换数据源?

答: 是的,基于springAop的方案来进行多数据源的管理和切换的,要想保证多个库的整体事务则需要分布式事务。

问:为什么使用了事务如@Transational就无法切换数据源?

答:开启了事务后,spring事物管理器会保证在事务下整个线程后续拿到的都是同一个connection。

问:事务下无法切换数据源我知道了,那我单库的事务的可以用吗?

答:完全可以的。 只要事务下不切换数据源就OK。

1.在启动类中添加DataSourceTransactionManagerAutoConfiguration.class

多数据源配置1

2.使用@MoreTransaction注解进行事务控制

@MoreTransaction({"master","slave1","slave2","slave4"}) 如果一个方法中用到多个数据源,需要把所有数据源配置到@MoreTransaction中,没配置的数据源会导致切库失败

@Service
public class UserServiceImpl implements UserService {


@Autowired
  private JdbcTemplate jdbcTemplate;


public List selectAll() {
    return  jdbcTemplate.queryForList("select * from user");
  }


@Override
  @MoreTransaction({"master","slave1","slave2","slave4"})
  public List selectByCondition() {
    return  jdbcTemplate.queryForList("select * from user where age >10");
  }
}

03. 常见数据源切换失败问题

1.使用事务@Transactional 不能使用事务@Transactional,否则数据源不会切换,使用的还是第一次加载的数据源;使用@MoreTransaction.

public UserService {


@Transactional
    @DbChoose("first")
    public void test1() {
        // do something
    }
}

2.使用this指针 本数据源切换使用的是AOP拦截,使用this会导致AOP失效。具体参考文档

public UserService {


@DbChoose("first")
    public void test1() {
         this.save();
    }
}

3.方法内部调用 查看以下示例 回答 外部调用userservice.test1()能在执行到test2()切换到second数据源吗?

public UserService {


@DbChoose("first")
    public void test1() {
         test2();
    }


@DbChoose("second")
    public void test2() {
        // do something
    }
}

04. 参考文档

1.springboot下mybatis多数据源的配置https://blog.csdn.net/nlx1450161741/article/details/115753151?spm=1001.2014.3001.5501

2.多数据源下事务控制https://blog.csdn.net/nlx1450161741/article/details/115873502?spm=1001.2014.3001.5501

3.this指针造成AOP失效https://blog.csdn.net/Zong_0915/article/details/126468545