Spring Boot中JdbcTemplate多数据源配置

作者简介:大家好,我是撸代码的羊驼,前阿里巴巴架构师,现某互联网公司CTO

联系v:sulny_ann(17362204968),加我进群,大家一起学习,一起进步,一起对抗互联网寒冬


在《Spring Boot中JdbcTemplate源码分析》中讲到了自动配置相关的源代码实现。基于Spring Boot自动配置默认配置的组件,我们可以来自定义JdbcTemplate的实例化。而多数据源的配置就是在此基础上实例化多个数据源和JdbcTemplate。

下面,我们来看具体的源代码实现。

依赖类库

关于依赖类库与集成JdbcTemplate时的一样,Spring Boot版本2.2.2.RELEASE。

相关pom依赖如下:

            org.springframework.boot        spring-boot-starter-web    
                org.springframework.boot        spring-boot-starter-jdbc                mysql        mysql-connector-java    
            org.projectlombok        lombok        true                org.springframework.boot        spring-boot-starter-test        test                                    org.junit.vintage                junit-vintage-engine                        

spring-boot-starter-jdbc是集成jdbc的依赖,mysql-connector-java是基于mysql的依赖类库。lombok是简化代码的工具类,如果不需要可去掉,并去掉类中相关的注解。

spring-boot-starter-test为单元测试依赖的类库,这里单元测试使用的是junit5,注意使用方法与junit4差别比较大。

配置application

application.properties配置如下:​​​​​​​

spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/spring?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=truespring.datasource.primary.username=rootspring.datasource.primary.password=root_123spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/spring1?serverTimezone=UTC&useUnicode=true\  &characterEncoding=utf-8&useSSL=truespring.datasource.secondary.username=rootspring.datasource.secondary.password=root_123spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

既然是多数据源,肯定要配置多个数据源的配置。与单数据源配置基本形式差不多。

需要注意的是第一个配置项的key为:spring.datasource.primary.jdbc-url。与单数据源时使用的spring.datasource.url有所区别。不然,启动时会抛出异常。

多数据源对应的Java配置

下面就需要我们自己来实例化DataSource和JdbcTemplate。相关的实例化也可参看源码解析文章中Spring Boot的实例化方式。

这里,我们的实现如下:​​​​​​​

@Configurationpublic class DataSourceConfig {
  @Primary  @Bean(name = "primaryDataSource")  @ConfigurationProperties(prefix="spring.datasource.primary")  public DataSource primaryDataSource() {    return DataSourceBuilder.create().build();  }
  @Bean(name = "secondaryDataSource")  @ConfigurationProperties(prefix="spring.datasource.secondary")  public DataSource secondaryDataSource() {    return DataSourceBuilder.create().build();  }
  @Bean(name="primaryJdbcTemplate")  public JdbcTemplate primaryJdbcTemplate (@Qualifier("primaryDataSource")  DataSource dataSource ) {    return new JdbcTemplate(dataSource);  }
  @Bean(name="secondaryJdbcTemplate")  public JdbcTemplate  secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource dataSource) {    return new JdbcTemplate(dataSource);  }
}

@Configuration声明该类为配置类。

@Primary指定当出现多个相同类型的实例化对象时,以该注解标注的为默认的。

@Bean实例化Bean,并将其注入到容器当中。这里分别实例化了primaryDataSource和secondaryDataSource两个DataSource,以Bean的名称来区分。

@ConfigurationProperties将前缀为spring.datasource.primary和前缀为spring.datasource.secondary的配置属性设置到对应的DataSource中。

随后实例化了两个JdbcTemplate,直接通过new关键字创建,并且把对应的DataSource作为构造参数传入。

经过该配置文件的配置,便有了两个JdbcTemplate。

实体类

实体类如下:​​​​​​​

@Datapublic class Order {
  private int id;
  private String orderNo;
  private int amount;}

@Data为Lombok的注解,自动生成一些默认的方法,比如属性的getter/setter方法。

数据库

关于数据库的DDL如下:​​​​​​​

CREATE TABLE `tb_order` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `amount` int(11) NOT NULL DEFAULT '1',  `order_no` varchar(64) NOT NULL DEFAULT '',  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

同样的表在两个数据库中进行创建。

接口定义

定义OrderService接口:​​​​​​​

public interface OrderService {
  /**   * 创建订单   * @param order 订单信息   * @return 记录数   */  int save(Order order);
  /**   * 保存到指定库   * @param order 订单信息   * @param jdbcTemplate jdbc   * @return   */  int save(Order order, JdbcTemplate jdbcTemplate);}

接口实现:​​​​​​​

@Service("orderService")public class OrderServiceImpl implements OrderService {
  @Resource  @Qualifier("primaryJdbcTemplate")  private JdbcTemplate jdbcTemplate;
  @Override  public int save(Order order) {    return jdbcTemplate.update("insert into tb_order(order_no, amount) values(?, ?)", order.getOrderNo(),        order.getAmount());  }
  @Override  public int save(Order order, JdbcTemplate secJdbcTemplate) {    if (secJdbcTemplate != null) {      return secJdbcTemplate.update("insert into tb_order(order_no, amount) values(?, ?)", order.getOrderNo(),          order.getAmount());    } else {      return jdbcTemplate.update("insert into tb_order(order_no, amount) values(?, ?)", order.getOrderNo(),          order.getAmount());    }  }}

在实现方法中,默认注入了主库的JdbcTemplate,同时在原来的save方法中新增了一个JdbcTemplate参数,可以根据是否传递该新的JdbcTemplate来决定使用哪个JdbcTemplate。

当然在此方法内也可以使用一个JdbcTemplate,然后根据参数动态的修改该JdbcTemplate指向的具体实现类。可以根据具体情况进行灵活运用。

单元测试

单元测试类如下:

@Slf4j@SpringBootTestclass OrderServiceTest {
  @Resource  private OrderService orderService;
  @Resource  @Qualifier("primaryJdbcTemplate")  private JdbcTemplate primaryJdbcTemplate;
  @Resource  @Qualifier("secondaryJdbcTemplate")  private JdbcTemplate secondaryJdbcTemplate;
  @Test  void save() {    Order order = new Order();    order.setOrderNo("N003");    order.setAmount(10000);    orderService.save(order, primaryJdbcTemplate);    orderService.save(order, secondaryJdbcTemplate);  }}

执行以上单元测试,两个库中的tb_order表分别插入了一条数据。关于其他增删改查操作,可参考保存方法进行扩展。

你可能感兴趣的:(springboot,springboot)