当前位置:   article > 正文

Springboot+druid+多数据源_springboot druid 多数据源

springboot druid 多数据源

背景:早期项目是springboot2.x + druid 的单数据源工程,其中使用了dblink的方式进行跨数据库访问。现在客户的机房搬迁,记账的下游数据库说是搬到不同区域,dblink的方式需要长期占用资源,需要修改成直连方式。

按照AI的指引采用:

 1.在Spring Boot中配置两个不同的Oracle数据源,你需要在配置类中分别定义两个数据源,并使用AbstractRoutingDataSource来路由到不同的数据源。以下是一个配置类的示例,展示了如何设置两个不同的Oracle数据源,并在应用中使用它们。1. 添加依赖确保pom.xml或build.gradle中包含Oracle JDBC驱动依赖。

Maven:

  1. <dependency>
  2. <groupId>com.oracle.database.jdbc</groupId>
  3. <artifactId>ojdbc8</artifactId>
  4. <version>版本</version>
  5. </dependency>

Gradle:

implementation 'com.oracle.database.jdbc:ojdbc8:版本'

2. 配置置文件在application.yml或application.properties中配置两个数据源的详细信息:

yaml:

  1. spring:
  2. datasource:
  3. primary:
  4. driver-class-name: oracle.jdbc.driver.OracleDriver
  5. url: jdbc:oracle:thin:@localhost:1521/orclpdb1
  6. username: system
  7. password: manager
  8. platform: oracle
  9. secondary:
  10. driver-class-name: oracle.jdbc.driver.OracleDriver
  11. url: jdbc:oracle:thin:@localhost:15222/orclpdb2
  12. username: scott
  13. password: tiger
  14. platform: oracle

3. 配置置类创建配置类来定义和配置两个数据源,并设置路由逻辑:

  1. @Configuration
  2. public class OracleDataSourceConfig {
  3. @Primary
  4. @Bean(name = "primaryDataSource")
  5. @ConfigurationProperties(prefix = "spring.datasource.primary")
  6. public DataSource primaryDataSource(DataSourceProperties properties) {
  7. return buildDataSource(properties, "primary");
  8. }
  9. @Bean(name = "secondaryDataSource")
  10. @ConfigurationProperties(prefix = "spring.datasource.secondary")
  11. public DataSource secondaryDataSource(DataSourceProperties properties) {
  12. return buildDataSource(properties, "secondary");
  13. }
  14. private DataSource buildDataSource(DataSourceProperties properties, String dataSourceName) {
  15. HikariDataSource ds = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
  16. ds.setPoolName(dataSourceName + "DataSource");
  17. return ds;
  18. }
  19. @Bean
  20. public AbstractRoutingDataSource dataSource(@Qualifier("primaryDataSource") DataSource primary, @Qualifier("secondaryDataSource") secondary) {
  21. AbstractRoutingDataSource router = new AbstractRoutingDataSource();
  22. Map<Object, Object> targetDataSources = new HashMap<>();
  23. targetDataSources.put("primary", primary);
  24. targetDataSources.put("secondary", secondary);
  25. router.setTargetDataSources(targetDataSources);
  26. return router;
  27. }
  28. }

4. 使用数据源在Service或Repository中,你可以通过@Qualifier指定数据源名称来使用特定的数据源:

  1. @Service
  2. public class UserService {
  3. private final UserRepository userRepository;
  4. @Autowired
  5. public UserService(@Qualifier("primaryDataSource") UserRepository userRepository) this.userRepository = userRepository;
  6. // your business code here
  7. }

对于动态路由到不同的数据源,你可以使用AbstractRoutingDataSource的机制,通过某种方式动态设置dataSourceLookupKey来决定使用哪个数据源。动态切换数据源示例你可以定义一个简单的策略来决定使用哪个数据源,比如基于用户ID的奇偶数或某些业务逻辑:

  1. public class DynamicDataSourceKeyResolver implements DataSourceLookup {
  2. @Override
  3. public DataSource determineCurrentLookupKey(Method method, Object[] args) {
  4. // 假设定一个逻辑,比如根据args[0](第一个参数)来决定数据源
  5. if ((Integer) args[0] % 2 == 0) return "primary";
  6. return "secondary";
  7. }
  8. }
  9. }

然后在你的服务中注入并设置这个Resolver:

  1. @Autowired
  2. public void setDataSourceLookup(DynamicDataSourceKeyResolver resolver) {
  3. ((AbstractRoutingDataSource) dataSource).setDefaultTargetDataSourceLookup(resolver);
  4. }

这样,每次调用到数据源的地方,都会根据你的逻辑动态切换到不同的数据源。请注意,实际应用中策略需根据具体业务需求调整。

这些配置还是太复杂了,看下引入dynamic-datasource-spring-boot-starter

dynamic-datasource-spring-boot-starter 是一个简化Spring Boot应用中配置多数据源管理的开源库。它支持动态切换数据源,可以方便地处理读写分离、分库等场景。下面是引入并使用 dynamic-datasource-spring-boot-starter 的简化配置步骤:

1. 添加依赖首先,在你的Spring Boot项目的pom.xml或build.gradle文件中加入 dynamic-datasource-spring-boot-starter 的依赖。

Maven:

  1. <dependency>
  2. <groupId>com.baomidou</groupId>
  3. <artifactId>dynamic-datasource-spring-boot-starter
  4. <version>最新版本号</version>
  5. </dependency>

2. YAML配置在application.yml文件中配置你的数据源,包括主数据源和其他数据源:

  1. spring:
  2. datasource:
  3. dynamic:
  4. primary: master
  5. strict: false # 是否严格匹配数据源名称,默认false
  6. datasource:
  7. master:
  8. driver-class-name: oracle.jdbc.driver.OracleDriver
  9. url: jdbc:oracle:thin:@localhost:1521/orclpdb1
  10. username: system
  11. password: manager
  12. slave:
  13. driver-class-name: oracle.jdbc.driver.OracleDriver
  14. url: jdbc:oracle:thin:@localhost:15222/orclpdb2
  15. username: scott
  16. password: tiger

3. 使用多数据源在业务代码中,你可以通过@DS注解器来指定使用特定的数据源,或者不指定时使用默认的数据源。

3.1. 在Service或Repository中指定数据源

  1. @Service
  2. public class UserService {
  3. @DS("slave")
  4. private final UserRepository userRepository;
  5. public UserService(UserRepository userRepository) {
  6. this.userRepository = userRepository;
  7. }
  8. // 业务逻辑...
  9. }

3.2. 动态切换数据源在需要动态切换数据源的场景下,可以通过DynamicDataSourceContextHolder来实现。

  1. public class SomeService {
  2. public void someMethodBasedOnCondition() {
  3. if (需要使用主数据源) {
  4. DataSourceContextHolder.setDataSourceType("master");
  5. } else {
  6. DataSourceContextHolder.setDataSourceType("slave");
  7. }
  8. // 执行数据库操作...
  9. DataSourceContextHolder.clearDataSourceType(); // 清除上下文,恢复默认数据源
  10. }
  11. }
  12. }

4. 自动配置切换策略dynamic-datasource-spring-boot-starter也支持自动路由策略,比如读写分离。

你可以配置master-slave来自动路由读写操作到主库,读操作到从库。

  1. spring:
  2. datasource:
  3. dynamic:
  4. strategy: master-slave

之前的单数据源可以通过配置druid的属性:

connectionProperties: config.decrypt=true;config.decrypt.key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIRTeF9hVfHv0qiOpzgQYW0/oQk6sQp278uwtBONYj2cKqF2OcBD8...==
指定数据库敏感信息不对称加解密的公钥

但是换成多数据源后,并不会触发解密密码字段。

AI后面给出的两三个办法都是行不通的。。。。

当然,如果你的应用需要配置多个Druid数据源,并且每个数据源的密码都需要通过自定义的解密方法解密,你可以扩展上面的配置方法以适应多数据源的场景。以下是实现多个Druid数据源并共用同一解密方法的一个示例:自定义解密工具类(与单数据源时相同)

  1. package com.example.utils;
  2. import org.springframework.stereotype.Component;
  3. @Component
  4. public class EncryptionUtils {
  5. public String decrypt(String encryptedText) {
  6. // 实际解密逻辑
  7. return encryptedText; // 示例返回,实际应替换为解密后明文
  8. }
  9. }
  1. package com.example.config;
  2. import com.alibaba.druid.pool.DruidDataSource;
  3. import com.example.utils.EncryptionUtils;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
  8. import org.springframework.boot.context.properties.ConfigurationProperties;
  9. import org.springframework.boot.context.properties.ConstructorBinding;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. @Configuration
  13. public class MultiDataSourceConfig {
  14. @Autowired
  15. private EncryptionUtils encryptionUtils;
  16. // 假设有两个数据源的配置类,你可以根据实际需要增加更多
  17. @ConstructorBinding
  18. @ConfigurationProperties(prefix = "spring.datasource.db1")
  19. public static class Db1DataSourceProperties {
  20. private String url;
  21. private String username;
  22. private String passwordEncrypted; // 加密的密码
  23. // getter & setter
  24. }
  25. @ConstructorBinding
  26. @ConfigurationProperties(prefix = "spring.datasource.db2")
  27. public static class Db2DataSourceProperties {
  28. private String url;
  29. private String username;
  30. private String passwordEncrypted; // 加密的密码
  31. // getter & setter
  32. }
  33. @Bean(name = "db1DataSource")
  34. public DataSource db1DataSource(Db1DataSourceProperties properties) {
  35. DruidDataSource dataSource = new DruidDataSource();
  36. dataSource.setUrl(properties.getUrl());
  37. dataSource.setUsername(properties.getUsername());
  38. dataSource.setPassword(encryptionUtils.decrypt(properties.getPasswordEncrypted()));
  39. // 其他配置
  40. return dataSource;
  41. }
  42. @Bean(name = "db2DataSource")
  43. public DataSource db2DataSource(Db2DataSourceProperties properties) {
  44. DruidDataSource dataSource = new DruidDataSource();
  45. dataSource.setUrl(properties.getUrl());
  46. dataSource.setUsername(properties.getUsername());
  47. dataSource.setPassword(encryptionUtils.decrypt(properties.getPasswordEncrypted()));
  48. // 其他配置
  49. return dataSource;
  50. }
  51. // 如果需要动态数据源路由,可参考dynamic-datasource-spring-boot-starter或自定义AbstractRoutingDataSource逻辑
  52. }

按照网上的passwordCallback也是不行

最后是下面的方法搞定了:

  1. Spring:
  2. datasource:
  3. dynamic:
  4. primary: master
  5. public-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI....==
  6. datasource:
  7. master:
  8. url: jdbc:oracle:thin:@127.0.0.1:1521/abcd
  9. password: ENC(加密后密文2)
  10. username: ENC(加密后密文1)
  11. slave:
  12. url: jdbc:oracle:thin:@127.0.0.1/defg
  13. password: 不加密原文

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/844163
推荐阅读
相关标签
  

闽ICP备14008679号