使用JdbcTemplate和dynamic-datasource-spring-boot-starter动态切换数据源操作数据库

本文介绍了如何使用JdbcTemplate和dynamic-datasource-spring-boot-starter库在SpringBoot应用中实现动态数据源切换。通过@DS注解在类或方法级别指定数据源,以及利用DynamicDataSourceContextHolder在运行时切换数据源,实现了对多个数据库的读写操作。示例代码展示了数据查询和插入的示例,并提供了配置动态数据源的步骤。

记录:414

场景:使用JdbcTemplate和dynamic-datasource-spring-boot-starter动态切换数据源操作数据库。

版本:JDK 1.8,Spring Boot 2.6.3,dynamic-datasource-spring-boot-starter-3.3.2。

源码:https://github.com/baomidou/dynamic-datasource-spring-boot-starter

dynamic-datasource-spring-boot-starter:一个基于springboot的快速集成多数据源的启动器。

1.动态数据源注解@DS作用在类上

1.1类GetDataDao

@DS("hub_a_db")
@Repository
public class GetDataDao {
  @Autowired
  private JdbcTemplate jt;
  public List<Map<String, Object>> getData() {
      String selectSQL = "SELECT CITY_ID,CITY_NAME,LAND_AREA,POPULATION, " +
              "  GROSS,CITY_DESCRIBE,DATA_YEAR,UPDATE_TIME " +
              "FROM t_city ";
      List<Map<String, Object>> data = jt.queryForList(selectSQL);
      return data;
  }
}

1.2类InsertDataDao

@DS("hub_b_db")
@Repository
public class InsertDataDao {
  @Autowired
  private JdbcTemplate jt;
  public void insertData(List<Map<String, Object>> data) {
    String insertSQL = "INSERT INTO t_city (\n" +
          "  CITY_ID,CITY_NAME,LAND_AREA,POPULATION,\n" +
          "  GROSS,CITY_DESCRIBE,DATA_YEAR,UPDATE_TIME)\n" +
          "VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
    jt.batchUpdate(insertSQL, new BatchPreparedStatementSetter() {
      @Override
      public void setValues(PreparedS
<think>我们面对的需求是:在若依微服务框架中,使用 dynamic-datasource-spring-boot-starter 来集成 ShardingSphere 的读写分离数据源。 但是注意,用户要求的是配置 dynamic-datasource-spring-boot-starter 以支持 ShardingSphere 的读写分离数据源,而不是直接用ShardingSphere替换动态数据源。 根据引用,dynamic-datasource-spring-boot-starter 本身是一个多数据源管理工具,而ShardingSphere是一个分库分表、读写分离的框架。 我们想要结合两者,即利用dynamic-datasource管理多个数据源(可能是不同的业务库),而每个业务库内部又需要ShardingSphere来实现读写分离。 然而,需要注意的是:ShardingSphere本身也可以管理多个数据源(分片数据源读写分离数据源),所以两者在功能上有重叠。因此,我们需要明确如何整合。 一种常见的整合方式是: 1. 使用dynamic-datasource管理多个数据源,其中每个数据源实际上是一个ShardingSphere数据源(已经配置了读写分离)。 2. 这样,我们可以通过dynamic-datasource切换不同的业务数据源(每个业务数据源内部由ShardingSphere管理读写分离)。 具体步骤: 步骤1:引入依赖 需要同时引入 dynamic-datasource-spring-boot-starter sharding-jdbc-spring-boot-starter 依赖。 步骤2:配置多个数据源(每个数据源对应一个ShardingSphere数据源) 在application.yml中配置dynamic-datasource数据源,但是每个数据源不是普通的DataSource,而是一个ShardingSphereDataSource。 但是,dynamic-datasource默认不支持直接配置ShardingSphere数据源,因此我们需要通过编程方式创建ShardingSphere数据源,并将其注册为dynamic-datasource数据源。 步骤3:通过编程方式创建ShardingSphere数据源 我们可以为每个需要读写分离的数据源分别配置一个ShardingSphere数据源,然后交给dynamic-datasource管理。 步骤4:使用@DS注解切换数据源,同时每个数据源内部由ShardingSphere实现读写分离。 但是,这种整合方式可能会比较复杂,因为ShardingSphere的配置本身也比较复杂。 另一种思路(更简单):将ShardingSphere的读写分离数据源作为一个普通数据源注册到dynamic-datasource中。 即,我们配置一个ShardingSphere数据源(它已经包含了主库从库,并实现了读写分离),然后将这个ShardingSphere数据源作为一个数据源(比如叫做"sharding-db")注册到dynamic-datasource中。 这样,我们可以用@DS("sharding-db")来使用这个数据源,同时在这个数据源内部实现了读写分离。 具体配置示例: 1. 引入依赖(注意版本兼容性): ```xml <!-- dynamic-datasource --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.6.1</version> </dependency> <!-- sharding-jdbc --> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.1.1</version> </dependency> ``` 2. 配置ShardingSphere的读写分离数据源(以其中一个业务库为例,假设我们有两个业务库:orderuser,每个业务库都需要读写分离): 但是注意,dynamic-datasourcesharding-jdbc的配置会有冲突,因为它们都会去创建数据源。因此,我们禁用sharding-jdbc的自动配置,改为手动创建ShardingSphere数据源。 3. 通过@Bean手动创建ShardingSphere数据源,并将其注册到dynamic-datasource中。 配置示例(application.yml): ```yaml spring: datasource: dynamic: primary: master # 设置默认的数据源或者数据源组,默认值即为master strict: false # 严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 datasource: master: # 这是默认数据源(可以是一个普通数据源,也可以是一个ShardingSphere数据源,但我们这里用普通数据源作为其他非分片库) url: jdbc:mysql://localhost:3306/master?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver # 注意:我们不在这里配置sharding-db,而是通过@Bean配置 ``` 然后,我们创建一个配置类,手动创建ShardingSphere数据源(例如,名为sharding-db),并将其注册到dynamic-datasource数据源集合中。 配置类示例: ```java @Configuration public class ShardingDataSourceConfig { @Autowired private DataSourceProperties dataSourceProperties; // 假设我们有一个主库两个从库,用于读写分离 @Bean @ConfigurationProperties(prefix = "spring.datasource.sharding.master") public DataSource masterDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.sharding.slave0") public DataSource slave0DataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.sharding.slave1") public DataSource slave1DataSource() { return DataSourceBuilder.create().build(); } // 创建ShardingSphere数据源(读写分离) @Bean public DataSource shardingDataSource() throws SQLException { // 实际数据源映射 Map<String, DataSource> dataSourceMap = new HashMap<>(); dataSourceMap.put("master0", masterDataSource()); dataSourceMap.put("slave0", slave0DataSource()); dataSourceMap.put("slave1", slave1DataSource()); // 读写分离规则 MasterSlaveRuleConfiguration masterSlaveRuleConfig = new MasterSlaveRuleConfiguration( "sharding-db", // 读写分离数据源的名称(逻辑数据源名) "master0", // 主库数据源名称 Arrays.asList("slave0", "slave1") // 从库数据源名称列表 ); // 创建ShardingSphere数据源 return MasterSlaveDataSourceFactory.createDataSource(dataSourceMap, masterSlaveRuleConfig, new Properties()); } // 将ShardingSphere数据源注册到dynamic-datasource中 @Bean public DynamicDataSourceProvider dynamicDataSourceProvider() { Map<String, DataSource> dataSourceMap = new HashMap<>(); try { // 将shardingDataSource加入到dynamic-datasource数据源列表中 dataSourceMap.put("sharding-db", shardingDataSource()); } catch (SQLException e) { throw new RuntimeException(e); } return new AbstractDataSourceProvider() { @Override public Map<String, DataSource> loadDataSources() { return dataSourceMap; } }; } } ``` 4. 在application.yml中,我们还需要配置dynamic-datasource的其他数据源(如果有的话)以及默认数据源。 5. 使用:在需要访问读写分离数据源的地方,使用@DS("sharding-db")注解。 注意:这种方式下,sharding-db这个数据源内部已经实现了读写分离(由ShardingSphere管理),而其他数据源(如master)则是一个普通数据源。 但是,上述配置中,我们手动创建了多个数据源(masterDataSource, slave0DataSource, slave1DataSource)并组合成ShardingSphere数据源,然后将其注册到dynamic-datasource中。 另外,我们还需要在配置文件中配置这些数据源的连接信息,例如: ```yaml spring: datasource: dynamic: primary: master # 默认数据源 datasource: master: url: jdbc:mysql://localhost:3306/master_db?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver sharding: master: url: jdbc:mysql://master-host:3306/db?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver slave0: url: jdbc:mysql://slave0-host:3306/db?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver slave1: url: jdbc:mysql://slave1-host:3306/db?useUnicode=true&characterEncoding=utf8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver ``` 注意:上面的配置中,我们使用了自定义的配置前缀(spring.datasource.sharding)来配置ShardingSphere所需的主从数据源。 另外,由于我们手动创建了数据源,所以不需要ShardingSphere的自动配置,因此可以排除ShardingSphere的自动配置类: ```java @SpringBootApplication(exclude = {ShardingSphereAutoConfiguration.class}) ``` 这样,我们就实现了将ShardingSphere的读写分离数据源作为一个数据源整合到dynamic-datasource中。 但是,请注意:如果同时有多个这样的读写分离数据源(比如多个业务库,每个库都需要读写分离),那么我们需要为每个读写分离数据源创建一个ShardingSphere数据源,并注册到dynamic-datasource中。 总结:通过将ShardingSphere数据源作为dynamic-datasource的一个数据源,我们可以在使用dynamic-datasource切换数据源的同时,在特定的数据源内部使用ShardingSphere实现读写分离。 注意:这种整合方式可能比较复杂,需要仔细处理依赖配置。同时,版本兼容性也是一个需要注意的问题。 如果遇到问题,建议查看官方文档或社区支持。 由于整合过程较为复杂,这里只提供了一个基本的思路示例。</think>### 配置 dynamic-datasource-spring-boot-starter 集成 ShardingSphere 读写分离数据源 #### 核心思路 将 ShardingSphere 的读写分离数据源作为 dynamic-datasource 的一个独立数据源进行管理,通过 `@DS` 注解实现动态切换[^1][^3]。 #### 配置步骤 1. **添加依赖** ```xml <!-- dynamic-datasource 核心依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.6.1</version> </dependency> <!-- ShardingSphere JDBC 依赖 --> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>5.3.2</version> </dependency> ``` 2. **配置数据源(application.yml)** ```yaml spring: shardingsphere: # 关闭ShardingSphere自动数据源创建 enabled: false datasource: names: master,slave0,slave1 # 物理数据源名称 master: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://master-host:3306/db username: root password: master-pwd slave0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://slave0-host:3306/db username: root password: slave-pwd slave1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc://slave1-host:3306/db username: root password: slave-pwd datasource: dynamic: primary: default # 默认数据源 strict: true # 严格匹配模式 datasource: default: # 普通数据源 url: jdbc:mysql://default-host:3306/default_db username: user password: pass sharding-db: # ShardingSphere读写分离数据源(通过Bean配置) ``` 3. **创建 ShardingSphere 数据源 Bean** ```java @Configuration public class ShardingDataSourceConfig { @Bean("shardingDataSource") public DataSource shardingDataSource( @Qualifier("master") DataSource master, @Qualifier("slave0") DataSource slave0, @Qualifier("slave1") DataSource slave1) { // 1. 创建数据源映射 Map<String, DataSource> dataSourceMap = new HashMap<>(); dataSourceMap.put("master", master); dataSourceMap.put("slave0", slave0); dataSourceMap.put("slave1", slave1); // 2. 配置读写分离规则 MasterSlaveRuleConfiguration ruleConfig = new MasterSlaveRuleConfiguration( "sharding-db", // 逻辑数据源名称 "master", // 主库名称 Arrays.asList("slave0", "slave1") // 从库列表 ); // 3. 创建ShardingSphere数据源 try { return MasterSlaveDataSourceFactory.createDataSource( dataSourceMap, ruleConfig, new Properties() ); } catch (SQLException e) { throw new RuntimeException("创建ShardingSphere数据源失败", e); } } } ``` 4. **注册到 dynamic-datasource** ```java @Configuration public class DynamicDataSourceConfig { @Autowired private DataSource shardingDataSource; // 注入ShardingSphere数据源 @Bean public DynamicDataSourceProvider dynamicDataSourceProvider() { return new AbstractDataSourceProvider() { @Override public Map<String, DataSource> loadDataSources() { Map<String, DataSource> dsMap = new HashMap<>(); // 添加ShardingSphere数据源 dsMap.put("sharding-db", shardingDataSource); return dsMap; } }; } } ``` 5. **使用读写分离数据源** ```java @Service public class OrderService { // 使用普通数据源 public void defaultOperation() { // 默认使用default数据源 } // 使用ShardingSphere读写分离数据源 @DS("sharding-db") // 动态切换数据源注解[^1][^3] public void readOperation() { // 自动路由到从库 jdbcTemplate.query("SELECT * FROM orders"); } @DS("sharding-db") @Transactional public void writeOperation() { // 自动路由到主库 jdbcTemplate.update("INSERT INTO orders (...) VALUES (...)"); } } ``` #### 关键配置说明 1. **数据源层级结构**: ``` Dynamic-Datasource ├── default (普通数据源) └── sharding-db (ShardingSphere数据源) ├── master (物理主库) ├── slave0 (物理从库1) └── slave1 (物理从库2) ``` 2. **读写分离规则**: -操作自动路由到主库 -操作自动负载均衡到从库 - 事务内强制走主库 3. **动态切换机制**: - `@DS("sharding-db")` 注解将当前操作切换到 ShardingSphere 数据源 - 未注解方法使用默认数据源[^1][^3] #### 性能优化建议 1. **从库负载均衡**: ```java // 在ShardingSphere配置中添加负载均衡策略 ruleConfig.setLoadBalanceAlgorithmType("ROUND_ROBIN"); ``` 2. **连接池配置**: ```yaml master: hikari: maximum-pool-size: 20 minimum-idle: 5 slave0: hikari: maximum-pool-size: 15 ``` 3. **强制主库读取**: ```java @DS("sharding-db") @Transactional public void readFromMaster() { // 通过HintManager强制走主库 try (HintManager hintManager = HintManager.getInstance()) { hintManager.setMasterRouteOnly(); jdbcTemplate.query("SELECT * FROM orders"); } } ``` > **验证方法**:在 SQL 前添加 `/* ShardingSphere hint: master */` 注释可验证主库路由
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值