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

记录: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(PreparedStatement ps, int i) throws SQLException {
          Map<String, Object> oneRow = data.get(i);
          ps.setObject(1, oneRow.get("CITY_ID"));
          ps.setObject(2, oneRow.get("CITY_NAME"));
          ps.setObject(3, oneRow.get("LAND_AREA"));
          ps.setObject(4, oneRow.get("POPULATION"));
          ps.setObject(5, oneRow.get("GROSS"));
          ps.setObject(6, oneRow.get("CITY_DESCRIBE"));
          ps.setObject(7, oneRow.get("DATA_YEAR"));
          ps.setObject(8, oneRow.get("UPDATE_TIME"));
      }
      @Override
      public int getBatchSize() {
          return data.size();
      }
    });
  }
}

2.动态数据源注解@DS作用在方法

@Repository
public class GetAndInsertDataDao {
  @Autowired
  private JdbcTemplate jt;
  @DS("hub_a_db")
  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;
  }
  @DS("hub_b_db")
  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(PreparedStatement ps, int i) throws SQLException {
              Map<String, Object> oneRow = data.get(i);
              ps.setObject(1, oneRow.get("CITY_ID"));
              ps.setObject(2, oneRow.get("CITY_NAME"));
              ps.setObject(3, oneRow.get("LAND_AREA"));
              ps.setObject(4, oneRow.get("POPULATION"));
              ps.setObject(5, oneRow.get("GROSS"));
              ps.setObject(6, oneRow.get("CITY_DESCRIBE"));
              ps.setObject(7, oneRow.get("DATA_YEAR"));
              ps.setObject(8, oneRow.get("UPDATE_TIME"));
          }
          @Override
          public int getBatchSize() {
              return data.size();
          }
      });
  }
}

3.使用DynamicDataSourceContextHolder操作动态数据源

无注解,在调用时,使用DynamicDataSourceContextHolder操作动态数据源。

@Repository
public class GetAndInsertDataByHolderDao {
  @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;
  }
  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(PreparedStatement ps, int i) throws SQLException {
              Map<String, Object> oneRow = data.get(i);
              ps.setObject(1, oneRow.get("CITY_ID"));
              ps.setObject(2, oneRow.get("CITY_NAME"));
              ps.setObject(3, oneRow.get("LAND_AREA"));
              ps.setObject(4, oneRow.get("POPULATION"));
              ps.setObject(5, oneRow.get("GROSS"));
              ps.setObject(6, oneRow.get("CITY_DESCRIBE"));
              ps.setObject(7, oneRow.get("DATA_YEAR"));
              ps.setObject(8, oneRow.get("UPDATE_TIME"));
          }
          @Override
          public int getBatchSize() {
              return data.size();
          }
      });
  }
}

4.测试类

4.1测试类

@Slf4j
@RestController
@RequestMapping("/hub/example/load01")
public class LoadController {
  @Autowired
  private GetDataDao getDataDao;
  @Autowired
  private InsertDataDao insertDataDao;
  @Autowired
  private GetAndInsertDataDao getAndInsertDataDao;
  @Autowired
  private GetAndInsertDataByHolderDao getAndInsertDataByHolderDao;
  /**
   * 1.动态数据源注解@DS作用在类上
   * */
  @GetMapping("/load01")
  public Object load01() {
      log.info("测试开始...");
      List<Map<String, Object>> data = getDataDao.getData();
      insertDataDao.insertData(data);
      log.info("测试结束...");
      return "执行成功";
  }
  /**
   * 2.动态数据源注解@DS作用在方法上
   * */
  @GetMapping("/load02")
  public Object load02() {
      log.info("测试开始...");
      List<Map<String, Object>> data = getAndInsertDataDao.getData();
      getAndInsertDataDao.insertData(data);
      log.info("测试结束...");
      return "执行成功";
  }
  /**
   * 3.使用DynamicDataSourceContextHolder操作动态数据源
   * */
  @GetMapping("/load03")
  public Object load03() {
      log.info("测试开始...");
      //1.使用hub_a_db数据源读数据
      DynamicDataSourceContextHolder.push("hub_a_db");
      List<Map<String, Object>> data = getAndInsertDataByHolderDao.getData();
      //2.使用hub_b_db数据源写数据
      DynamicDataSourceContextHolder.poll();
      DynamicDataSourceContextHolder.push("hub_b_db");
      getAndInsertDataByHolderDao.insertData(data);
      log.info("测试结束...");
      return "执行成功";
  }
}

4.2测试URL

URL01: http://127.0.0.1:18204/hub-example/hub/example/load01/load01

URL02: http://127.0.0.1:18204/hub-example/hub/example/load01/load02

URL03: http://127.0.0.1:18204/hub-example/hub/example/load01/load03

5.基础配置

5.1配置动态数据源

spring:
  jackson:
    time-zone: GMT+8
  datasource:
    dynamic:
      primary: hub_a_db
      strict: false
      datasource:
        hub_a_db:
          url: jdbc:mysql://127.0.0.1:3306/hub_a_db
          username: hub_a
          password: 12345678
          driver-class-name: com.mysql.cj.jdbc.Driver
        hub_b_db:
          url: jdbc:mysql://127.0.0.1:3306/hub_b_db
          username: hub_b
          password: 12345678
          driver-class-name: com.mysql.cj.jdbc.Driver

5.2动态数据源依赖包

<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  <version>3.3.2</version>
</dependency>

5.3建表语句

CREATE TABLE t_city (
  CITY_ID BIGINT(16) NOT NULL COMMENT '唯一标识',
  CITY_NAME VARCHAR(64) COLLATE utf8_bin NOT NULL COMMENT '城市名',
  LAND_AREA DOUBLE DEFAULT NULL COMMENT '城市面积',
  POPULATION BIGINT(16) DEFAULT NULL COMMENT '城市人口',
  GROSS DOUBLE DEFAULT NULL COMMENT '生产总值',
  CITY_DESCRIBE VARCHAR(512) COLLATE utf8_bin DEFAULT NULL COMMENT '城市描述',
  DATA_YEAR VARCHAR(16) COLLATE utf8_bin DEFAULT NULL COMMENT '数据年份',
  UPDATE_TIME DATETIME DEFAULT NULL COMMENT '更新时间'
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='城市信息表';

以上,感谢。

2023年4月17日

ShardingSphere是一款开源的分布式数据库中间件,可以实现对关系型数据库的分库分表、读写分离、分布式事务等功能。而dynamic-datasource-spring-boot-starter是一个基于Spring Boot动态数据源组件,可以动态切换数据源。如果需要将这两个组件整合起来使用,可以按照以下步骤进行操作: 1. 引入依赖 在项目的pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-core</artifactId> <version>${sharding-sphere-version}</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>${dynamic-datasource-version}</version> </dependency> ``` 其中,${sharding-sphere-version}为ShardingSphere的版本号,${dynamic-datasource-version}为dynamic-datasource-spring-boot-starter的版本号。 2. 配置数据源 在application.yml中配置数据源信息,包括ShardingSphere的分库分表规则动态数据源的配置信息。 ```yaml spring: shardingsphere: datasource: names: ds0,ds1 ds0: driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/db0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC username: root password: root ds1: driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC username: root password: root sharding: tables: user: actual-data-nodes: ds${0..1}.user_${0..1} table-strategy: inline: sharding-column: id algorithm-expression: user_${id % 2} key-generator: column: id type: SNOWFLAKE ``` 其中,names为数据源名称,actual-data-nodes为ShardingSphere的分库分表规则,table-strategy为分表策略,key-generator为主键生成策略。 3. 配置动态数据源DynamicDataSourceAutoConfiguration中配置动态数据源。 ```java @Configuration public class DynamicDataSourceAutoConfiguration { @Bean @ConfigurationProperties(prefix = "spring.datasource.ds0") public DataSource ds0() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.ds1") public DataSource ds1() { return DataSourceBuilder.create().build(); } @Bean @Primary public DynamicDataSource dataSource(DataSource ds0, DataSource ds1) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put("ds0", ds0); targetDataSources.put("ds1", ds1); return new DynamicDataSource(ds0, targetDataSources); } } ``` 其中,ds0ds1分别对应于ShardingSphere中的ds0ds1数据源DynamicDataSource动态数据源的实现类。 4. 测试 在测试类中使用@Autowired注解注入DataSource,并使用JdbcTemplate进行数据操作。 ```java @SpringBootTest public class ShardingTest { @Autowired private DataSource dataSource; @Test public void test() { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.update("insert into user (name, age) values (?, ?)", "张三", 20); jdbcTemplate.update("insert into user (name, age) values (?, ?)", "李四", 30); List<Map<String, Object>> userList = jdbcTemplate.queryForList("select * from user"); System.out.println(userList); } } ``` 运行测试类,可以看到数据成功插入到两个库的两张表中,并且查询结果也正确。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值