作者简介:大家好,我是撸代码的羊驼,前阿里巴巴架构师,现某互联网公司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.properties配置如下:
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/spring?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.primary.username=root
spring.datasource.primary.password=root_123
spring.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=true
spring.datasource.secondary.username=root
spring.datasource.secondary.password=root_123
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
既然是多数据源,肯定要配置多个数据源的配置。与单数据源配置基本形式差不多。
需要注意的是第一个配置项的key为:spring.datasource.primary.jdbc-url。与单数据源时使用的spring.datasource.url有所区别。不然,启动时会抛出异常。
下面就需要我们自己来实例化DataSource和JdbcTemplate。相关的实例化也可参看源码解析文章中Spring Boot的实例化方式。
这里,我们的实现如下:
@Configuration
public 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。
实体类如下:
@Data
public 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
@SpringBootTest
class 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表分别插入了一条数据。关于其他增删改查操作,可参考保存方法进行扩展。