当前位置: 首页 > news >正文

如何使用自定义@DS注解切换数据源

目录

方法一:使用Spring的@Transactional注解与动态数据源

1.定义多个数据源:

2.配置动态数据源:

3.实现动态数据源类:

4.使用AOP切换数据源:

5.创建一个自定义注解@DS。

6.使用自定义 @DS 注解切换 

⚠️ 手动方案的重要缺陷

生产环境建议

总结


在Spring框架中,通过使用@DS注解切换数据源是一种常见需求,尤其是在使用多数据源的微服务架构中。@DS并不是Spring框架原生提供的注解,但可以通过一些方式实现类似功能。通常,我们可以借助AOP(面向切面编程)和动态数据源的实现来达到切换数据源的目的。

方法一:使用Spring的@Transactional注解与动态数据源

1.定义多个数据源

首先,定义你的数据源配置。

@Configuration
public class DataSourceConfig {@Bean@ConfigurationProperties("spring.datasource.druid.master")public DataSource firstDataSource() {return DataSourceBuilder.create().build();}@Bean@ConfigurationProperties("spring.datasource.druid.slave")@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")public DataSource secondDataSource() {return DataSourceBuilder.create().build();}
}

 你的yml中也要有相应的数据库连接信息

spring:# 数据源配置datasource:type: com.alibaba.druid.pool.DruidDataSourcedruid:# 从数据源oracle: # Oracle从库url: jdbc:oracle:thin:@//localhost:1521/ORCLusername: scottpassword: tigerdriver-class-name: oracle.jdbc.OracleDriver # 必须指定!# mysql主库数据源master:url: jdbc:mysql://127.0.0.1:3306/axhyh-xs-local?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver # 必须指定!# 初始连接数initialSize: 5# 最小连接池数量minIdle: 10# 最大连接池数量maxActive: 20# 配置获取连接等待超时的时间maxWait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 300000# 配置一个连接在池中最大生存的时间,单位是毫秒maxEvictableIdleTimeMillis: 900000# 配置检测连接是否有效validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsewebStatFilter:enabled: truestatViewServlet:enabled: true# 设置白名单,不填则允许所有访问allow:url-pattern: /druid/*# 控制台管理用户名和密码login-username:login-password:filter:stat:enabled: true# 慢SQL记录log-slow-sql: trueslow-sql-millis: 1000merge-sql: truewall:config:multi-statement-allow: true
  1. 2.配置动态数据源

     创建一个动态数据源的Bean。

@Configuration
public class DynamicDataSourceConfig {@Autowiredprivate DataSource firstDataSource;@Autowiredprivate DataSource secondDataSource;@Beanpublic DataSource dynamicDataSource() {DynamicDataSource dynamicDataSource = new DynamicDataSource();Map<Object, Object> dataSourceMap = new HashMap<>();dataSourceMap.put("dataSource1", firstDataSource);dataSourceMap.put("dataSource2", secondDataSource);dynamicDataSource.setTargetDataSources(dataSourceMap);dynamicDataSource.setDefaultTargetDataSource(firstDataSource); // 默认数据源return dynamicDataSource;}
}
    3.实现动态数据源类

    创建一个动态数据源类。

    public class DynamicDataSource extends AbstractRoutingDataSource {private static final ThreadLocal<String> dataSourceKey = new NamedThreadLocal<>("dataSourceKey");public static void setDataSourceKey(String key) {dataSourceKey.set(key);}public static String getDataSourceKey() {return dataSourceKey.get();}public static void clearDataSourceKey() {dataSourceKey.remove();}@Overrideprotected Object determineCurrentLookupKey() {return getDataSourceKey();}
    }
    4.使用AOP切换数据源

    通过AOP在方法执行前后切换数据源。

    @Aspect
    @Component
    public class DataSourceAspect {@Before("@annotation(ds)") // 在有@DS注解的方法执行前切换数据源public void changeDataSource(JoinPoint point, DS ds) throws Throwable {String dsId = ds.value(); // 获取注解中的值,即数据源标识符DynamicDataSource.setDataSourceKey(dsId); // 切换数据源}@After("@annotation(ds)") // 在有@DS注解的方法执行后清除数据源标识符,以避免影响其他方法执行时的数据源选择。public void clearDataSource(JoinPoint point, DS ds) {DynamicDataSource.clearDataSourceKey(); // 清除数据源标识符,恢复默认或上一个数据源设置。}
    }
    5.创建一个自定义注解@DS
    @Target(ElementType.METHOD) // 指定注解可以应用于方法上。
    @Retention(RetentionPolicy.RUNTIME) // 运行时保留注解信息。
    public @interface DS { String value(); // 数据源标识符,例如 "dataSource1", "dataSource2" 等。 需要在配置中定义。 对应到具体的dataSourceMap的key值。 例如:@DS("dataSource1") 表示使用第一个数据源。 需要在DynamicDataSource的dataSourceMap中设置对应的key值。 例如:dataSourceMap.put("dataSource1", firstDataSource); 对应这里的"dataSource1"。 确保这里的key值与@DS注解中的value值一致。这样在切换数据源时才能正确匹配到对应的数据源。 例如:@DS("dataSource1") 表示使用第一个数据源。 需要在DynamicDataSource的dataSourceMap中设置对应的key值。 例如:dataSourceMap.put("dataSource1", firstDataSource); 这样在切换数据源时才能正确匹配到对应的数据源。 确保这里的key值与@DS注解中的value值一致。这样在切换数据
    6.使用自定义 @DS 注解切换 
    // 使用MySQL数据源
    @Service
    public class UserService {@DS("master") // 切换到MySQL数据源public List<User> getUsers() {return userMapper.selectList(); // 操作MySQL}
    }// 使用Oracle数据源
    @Service
    public class OrderService {@DS("oracle") // 切换到Oracle数据源public List<Order> getOrders() {return orderMapper.selectList(); // 操作Oracle}
    }

    ⚠️ 手动方案的重要缺陷

    虽然能实现基础切换,但相比配置多数据源dynamic-datasource存在明显短板:

    ​问题​手动方案(配置一)配置二(dynamic-datasource)
    ​多数据库驱动冲突​需手动指定driver-class-name(易遗漏)自动隔离驱动
    ​连接池配置继承​需为每个数据源单独配置连接池参数通过spring.datasource.druid全局统一配置
    ​分布式事务支持​需自研Seata/XA集成(复杂)dynamic.seata: true一键开启
    ​读写分离​需手写AOP逻辑内置@DS("slave")自动负载均衡
    ​多租户支持​需完全自研内置多租户路由策略
    ​监控集成​需单独配置每个Druid监控自动聚合所有数据源监控

    生产环境建议

    1. ​简单场景(开发/测试环境)​
      可用手动方案快速验证多数据库切换,但注意:

      • 严格检查所有数据源的 driver-class-name
      • 为每个数据源重复配置连接池参数(易错!)
    2. ​生产环境严肃建议​​ → ​​采用配置二(dynamic-datasource)​
      添加依赖后直接配置:

    spring:datasource:dynamic:primary: mysql # 默认数据源datasource:mysql: url: jdbc:mysql://localhost:3306/dboracle:url: jdbc:oracle:thin:@//localhost:1521/ORCLdruid: # 全局连接池配置initial-size: 5max-active: 20# ...其他参数自动继承到所有数据源

    使用内置注解无感切换:

    @DS("mysql") // 无需自研注解
    public void mysqlQuery() { ... }@DS("oracle") // 自动处理驱动隔离和连接池
    public void oracleUpdate() { ... }

    总结

    • ​能实现但繁琐​​:手动方案可通过显式声明驱动和重复配置实现多库切换
    • ​生产级差距​​:缺少连接池继承、驱动自动隔离、分布式事务等关键能力
    • ​终极建议​​:​​优先使用 dynamic-datasource​​,它专为解决此类问题设计,可节省 80% 的调试成本。尤其涉及 Oracle 等商业数据库时,驱动兼容性问题在手动方案中极易引发生产事故。

    http://www.dtcms.com/a/308806.html

    相关文章:

  1. 中小企业数据保护指南:如何用群晖NAS构建高效备份体系?
  2. pytorch程序语句固定开销分析
  3. hive新增列之后插入新数据时,新列为NULL的解决办法
  4. 火焰图(Flame Graph)深度指南:CPU性能分析与瓶颈定位
  5. 2025.8-12月 AI相关国内会议
  6. C基础 12_day
  7. XL2422 无线收发芯片,可用于遥控玩具和智能家居等应用领域
  8. 网络层概述
  9. LLM残差流为何会超过1?
  10. Lombok 字段魔法:用 @FieldDefaults 解锁“隐身+锁死”双重特效
  11. Linux731 shell工具;[]字符
  12. kettle插件-kettle http client plus插件,轻松解决https接口无法调用文件流下载问题
  13. 数据库连接池性能优化实战
  14. 【RH134 问答题】第 13 章 运行容器
  15. 谷歌浏览器之f12打开控制台debugger模式实现条件控制打印输出及字节数组条件
  16. Java 并发编程基础概念与常见问题梳理
  17. 电商项目_性能优化_高并发缓存一致性
  18. 【Unity笔记04】数据持久化
  19. HTM 5 的离线储存的使用和原理
  20. Unity游戏开发中的3D数学基础详解
  21. MATLAB 2025a的下载以及安装,安装X310的测试附加功能(附加安装包)
  22. 因为想开发新项目了~~要给老Python项目整个虚拟环境
  23. 旋转花键在机械加工中心ATC装置中有什么优势?
  24. 01 全基因组关联分析原理
  25. vlan技术
  26. 【PHP属性详解:从基础到只读的完全指南】
  27. 企业智脑1.3.1技术升级全面解读:AI笔记引擎如何重塑企业知识管理范式
  28. 计算机系统基础与操作系统笔记
  29. Spring Boot Admin 监控模块笔记-实现全链路追踪
  30. 另外几种语言挑战100万行字符串文本排序