记springboot项目中出现@DS多数据源失效场景

多数据源依赖

<!-- dynamic-datasource 多数据源-->
<dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
</dependency>

配置文件

# 数据源配置
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
    dynamic:
      # 性能分析插件(有性能损耗 不建议生产环境使用)
      p6spy: true
      # 设置默认的数据源或者数据源组,默认值即为 master
      primary: master
      # 严格模式 匹配不到数据源则报错
      strict: true
      datasource:
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://***.***.***:3306/master?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
          username: master
          password: master
          type: com.alibaba.druid.pool.DruidDataSource
          druid:
            initial-size: 20
            min-idle: 20
            max-active: 100
            max-wait: 60000
            pool-prepared-statements: false
            max-pool-prepared-statement-per-connection-size: 20
            timeBetweenEvictionRunsMillis: 60000
            validationQuery: SELECT 1 FROM dual
            filter: stat,wall,log4j
        slave:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://***.***.***:3306/slave?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
          username: slave
          password: slave
          type: com.alibaba.druid.pool.DruidDataSource
          druid:
            initial-size: 20
            min-idle: 20
            max-active: 100
            max-wait: 60000
            pool-prepared-statements: false
            max-pool-prepared-statement-per-connection-size: 20
            timeBetweenEvictionRunsMillis: 60000
            validationQuery: SELECT 1 FROM dual
            filter: stat,wall,log4j

      hikari:
        # 最大连接池数量
        maxPoolSize: 20
        # 最小空闲线程数量
        minIdle: 10
        # 配置获取连接等待超时的时间
        connectionTimeout: 30000
        # 校验超时时间
        validationTimeout: 5000
        # 空闲连接存活最大时间,默认10分钟
        idleTimeout: 600000
        # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
        maxLifetime: 1800000
        # 连接测试query(配置检测连接是否有效)
        connectionTestQuery: SELECT 1
        # 多久检查一次连接的活性
        keepaliveTime: 30000

--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring:
  redis:
    # 地址
    host: localhost
    # 端口,默认为6379
    port: 6379
    # 数据库索引
    database: 0
    # 密码(如没有密码请注释掉)
    # password:
    # 连接超时时间
    timeout: 10s
    # 是否开启ssl
    ssl: false

redisson:
  # redis key前缀
  keyPrefix:
  # 线程池数量
  threads: 4
  # Netty线程池数量
  nettyThreads: 8
  # 单节点配置
  singleServerConfig:
    # 客户端名称
    clientName: ${huiren.name}
    # 最小空闲连接数
    connectionMinimumIdleSize: 8
    # 连接池大小
    connectionPoolSize: 32
    # 连接空闲超时,单位:毫秒
    idleConnectionTimeout: 10000
    # 命令等待超时,单位:毫秒
    timeout: 3000
    # 发布和订阅连接池大小
    subscriptionConnectionPoolSize: 50

--- # mail 邮件发送
mail:
  enabled: false
  host: smtp.163.com
  port: 465
  # 是否需要用户名密码验证
  auth: true
  # 发送方,遵循RFC-822标准
  from: xxx@163.com
  # 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
  user: xxx@163.com
  # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
  pass: xxxxxxxxxx
  # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
  starttlsEnable: true
  # 使用SSL安全连接
  sslEnable: true
  # SMTP超时时长,单位毫秒,缺省值不超时
  timeout: 0
  # Socket连接超时值,单位毫秒,缺省值不超时
  connectionTimeout: 0

--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://wind.kim/doc/start 文档地址 各个厂商可同时使用
sms:
  # 阿里云 dysmsapi.aliyuncs.com
  alibaba:
    #请求地址 默认为 dysmsapi.aliyuncs.com 如无特殊改变可以不用设置
    requestUrl: dysmsapi.aliyuncs.com
    #阿里云的accessKey
    accessKeyId: xxxxxxx
    #阿里云的accessKeySecret
    accessKeySecret: xxxxxxx
    #短信签名
    signature: 测试
  tencent:
    #请求地址默认为 sms.tencentcloudapi.com 如无特殊改变可不用设置
    requestUrl: sms.tencentcloudapi.com
    #腾讯云的accessKey
    accessKeyId: xxxxxxx
    #腾讯云的accessKeySecret
    accessKeySecret: xxxxxxx
    #短信签名
    signature: 测试
    #短信sdkAppId
    sdkAppId: appid
    #地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
    territory: ap-guangzhou

使用方式

在service具体实现类或者方法上添加 @DS("slave“) 即可切换数据源(slave为配置文件里配置的数据源名称)

@DS("slave")
public interface OsuSlaveHomeMapper {

    Integer selectAttendance(@Param("scheduleName") String scheduleName);

    Integer selectTotalSignNumber();

    @DS("master")
    int selectOnModeAttendNum();
}

失效场景解决方案

使用动态数据源(@DS)时,@Transactional使用可能会照成@DS失效。
解决方案:

  1. 去掉事务(不建议)

  2. @DS切换数据源的方法添加事务传播属性@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)

  3. 去掉@DS切换数据源方法的事务,主方法用@DSTransactional注解。

@DS注解加到mapper接口、service接口、service方法里都不生效

解决方案:

  • 添加到service实现类或者实现类里具体的方法上。

在同一个实现类中,一个非DS注解的常规方法里调用@DS注解的方法可能失效
解决方案:

  • 将该DS注解方法定义在不同的类中,通过bean注入的方式调用

Comment