动态数据源与多数据库简单使用

写在前面

本次操作使用MyBatis动态数据源和多数据库的支持,仅仅记录自己理解的关键部分,如有错误,欢迎指正教导,我一定认真吸取!

动态数据源

引入依赖

<!-- mysql驱动包 -->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.48</version>
</dependency>
<!-- oracle驱动包 -->
<dependency>
 <groupId>com.oracle</groupId>
    <artifactId>ojdbc6</artifactId>
    <version>11.2.0.3</version>
</dependency>
<!-- 动态数据源 -->
<dependency>
   <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

数据源配置需要使用动态数据源格式,这里的master数据源是mysql数据库,slave数据源是oracle数据库

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    dynamic:
      #设置默认的数据源或者数据源组,默认值即为master
      primary: master
      datasource:
        master:
          username: user
          password: password
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:8904/COMMON_ORG?characterEncoding=UTF-8&serverTimezone=UTC
          minimum-idle: 30
          maximum-pool-size: 50
          auto-commit: true
          pool-name: DatebookHikariCP
          idle-timeout: 1600000
          max-lifetime: 180000
          connection-timeout: 30000
          connection-test-query: SELECT 1
        slave:
          username: username
          password: password
          driver-class-name: oracle.jdbc.OracleDriver
          url: "jdbc:oracle:thin:@127.0.0.1:1521/uomqkjdb"
          minimum-idle: 30
          maximum-pool-size: 50
          auto-commit: true
          pool-name: DatebookHikariCP
          idle-timeout: 1600000
          max-lifetime: 180000
          connection-timeout: 30000
          connection-test-query: SELECT 1

微服务默认使用主数据源(primary),当需要使用其他从数据源时,可以使用如下@DS注释来切换到指定数据源

@DS("slave")
public interface TestMapper extends BaseMapper<TestEntity> {

	List<TestVo> getTestVo(Page<TestVo> page, @Param("value") String value,@Param("isWhiteList")  Integer isWhiteList);
}

需要注意的是,@DS注释最好使用在Mapper.java的类名或方法上,已经确认的是,在@Transactional涵盖下,使用@DS切换数据源将会失效。

多数据库

由于还没有实际操作,使用配置待补充,目前已知在Mybaitis配置中,配置支持的数据库ID

@Bean
public DatabaseIdProvider getDatabaseIdProvider() {
	DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
	Properties properties = new Properties();
	properties.setProperty(ORACLE, "oracle");
	properties.setProperty(MYSQL, "mysql");
	databaseIdProvider.setProperties(properties);
	return databaseIdProvider;
}

在Mapper.xml中使用,为标签指定databaseId。
例如:

<select id="selectString" resultType="java.lang.String">
    select
    <if test="_databaseId==mysql">
        concat(a.name,a.age)
    </if>
    <if test="_databaseId==oracle">
        a.name||a.age
    </if>
    from tb_user a
</select>

再例如:

<select id="selectString" resultType="java.lang.String"  databaseId="mysql">
    select concat(a.name,a.age)
    from tb_user a
</select>

<select id="selectString" resultType="java.lang.String"  databaseId="oracle">
    select  a.name||a.age
    from tb_user a
</select>

无论是哪种方式指定databaseId,实际执行的时候使用哪个,取决于sqlSession中databaseId的属性,而该属性在应用服务启动初始化的时候,在org.mybatis.spring.SqlSessionFactoryBean的buildSqlSessionFactory()方法中根据当前数据源(dataSource)和databaseIdProvider配置确定,在服务运行时,不会再随着动态数据源的切换而切换

--org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory方法截取
if (this.databaseIdProvider != null) {
    try {
         configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
     } catch (SQLException var24) {
         throw new NestedIOException("Failed getting a databaseId", var24);
     }
 }

同时使用动态数据源与多数据库

根据上面的内容我们可以知道,动态数据源多数据库支持同时使用的时候,并不如想象中的完美配合。

依照本章动态数据源部分的场景(即在Mapper.java中切换数据源为slave的oracle数据库),主数据源(primary)设置的是mysql数据库,那么在服务启动的时候就会初始化databaseId为mysql,那么如果我们如下同时指定多数据源格式查询语句时,会优先匹配到第一个databaseId="mysql"的脚本执行,此时使用oracle数据源来执行mysql语句,势必导致执行异常。

<select id="selectString" resultType="java.lang.String"  databaseId="mysql">
    select concat(a.name,a.age)
    from tb_user a
</select>

<select id="selectString" resultType="java.lang.String"  databaseId="oracle">
    select  a.name||a.age
    from tb_user a
</select>

即使注释掉databaseId="mysql"的脚本,也不会使用databaseId="oracle"的脚本,反而会报错 Invalid bound statement (not found)

这其中涉及到mybatis的筛选机制,在初始化的时候(保留怀疑),会收集所有执行语句,如果有同名的,会保留指定databaseId的部分(或片段),如果同名执行语句中同时包含指定databaseId的和未指定的,那么会抛弃未指定的执行语句。

因此,如果在一个Mapper.java方法中切换了数据源,表明已经确定了该方法所用的数据库类型,因此在Mapper.xml中写sql语句的时候,就没有必要再指定databaseId属性,也可以避免不必要的麻烦。如下配置公共的执行语句,虽然sqlSession中databaseId为mysql,但不会再使用databaseId来作为执行语句的筛选条件

<select id="selectString" resultType="java.lang.String">
    select  a.name||a.age
    from tb_user a
</select>

至于想要databaseId如何随着动态数据源的切换而切换,目前还没想到好的办法,暂时或者基本上也遇不到这样的需求场景。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值