作者簡介:大家好,我是擼代碼的羊駝,前阿里巴巴架構師,現某互聯網公司CTO
聯系v:sulny_ann(17362204968),加我進群,大家一起學習,一起進步,一起對抗互聯網寒冬
在《Spring Boot中JdbcTemplate源碼分析》中講到了自動配置相關的源代碼實現。基于Spring Boot自動配置默認配置的組件,我們可以來自定義JdbcTemplate的實例化。而多數據源的配置就是在此基礎上實例化多個數據源和JdbcTemplate。
下面,我們來看具體的源代碼實現。
依賴類庫
關于依賴類庫與集成JdbcTemplate時的一樣,Spring Boot版本2.2.2.RELEASE。
相關pom依賴如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--數據庫連接相關-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
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=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有所區別。不然,啟動時會拋出異常。
多數據源對應的Java配置
下面就需要我們自己來實例化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表分別插入了一條數據。關于其他增刪改查操作,可參考保存方法進行擴展。