本文介绍 Spring Boot 2 配置多个 SQL 数据源的方法。
目录
- 开发环境
- 基础示例
- 总结
开发环境
- Oracle JDK 1.8.0_201
- Apache Maven 3.6.0
- IntelliJ IDEA (Version 2018.3.3)
- MySQL 5.6.38
基础示例
创建 3 个字符集为
utf8 -- UTF-8 Unicode
的 MySQL 数据库first
,second
,third
。为这 3 个数据库分别创建各自的管理员用户。
2.1 first
数据库管理员:
CREATE USER 'first_admin'@'127.0.0.1' IDENTIFIED BY '111111';
GRANT SELECT, INSERT, UPDATE, REFERENCES, DELETE, CREATE, DROP, ALTER, INDEX, TRIGGER, CREATE VIEW, SHOW VIEW, EXECUTE, ALTER ROUTINE, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, EVENT ON `first`.* TO 'first_admin'@'127.0.0.1';
GRANT GRANT OPTION ON `first`.* TO 'first_admin'@'127.0.0.1';
2.2 second
数据库管理员:
CREATE USER 'second_admin'@'127.0.0.1' IDENTIFIED BY '222222';
GRANT SELECT, INSERT, UPDATE, REFERENCES, DELETE, CREATE, DROP, ALTER, INDEX, TRIGGER, CREATE VIEW, SHOW VIEW, EXECUTE, ALTER ROUTINE, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, EVENT ON `second`.* TO 'second_admin'@'127.0.0.1';
GRANT GRANT OPTION ON `second`.* TO 'second_admin'@'127.0.0.1';
2.3 third
数据库管理员:
CREATE USER 'third_admin'@'127.0.0.1' IDENTIFIED BY '333333';
GRANT SELECT, INSERT, UPDATE, REFERENCES, DELETE, CREATE, DROP, ALTER, INDEX, TRIGGER, CREATE VIEW, SHOW VIEW, EXECUTE, ALTER ROUTINE, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, EVENT ON `third`.* TO 'third_admin'@'127.0.0.1';
GRANT GRANT OPTION ON `third`.* TO 'third_admin'@'127.0.0.1';
- 在这 3 个数据库中分表创建 3 张不同含义的表。
3.1 first
数据库中创建客户信息表:
CREATE TABLE `customer` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
`name` varchar(16) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '姓名' ,
`phone_number` varchar(16) CHARACTER SET utf8 NULL DEFAULT '' COMMENT '电话号码' ,
PRIMARY KEY (`id`)
)
COMMENT='顾客';
3.2 second
数据库中创建零售商信息表:
CREATE TABLE `retailer` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
`name` varchar(32) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '名称' ,
`contact` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '联系方式' ,
PRIMARY KEY (`id`)
)
COMMENT='零售商';
3.3 third
数据库中创建工厂信息表:
CREATE TABLE `factory` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键' ,
`name` varchar(32) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '名称' ,
`address` varchar(128) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '地址' ,
PRIMARY KEY (`id`)
)
COMMENT='工厂';
创建 Spring Boot 工程,参考:IntelliJ IDEA 创建 Spring Boot 工程。
在生成的
pom
文件中添加以下依赖:
-
spring-boot-starter-jdbc
:Spring JDBC 支持 -
mysql-connector-java
:MySQL 数据库驱动 -
junit
:单元测试
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.4.RELEASE
tutorial.spring.boot
spring-boot-data-source
0.0.1-SNAPSHOT
spring-boot-data-source
Spring Boot Multiple Data Source
1.8
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
5.1.47
junit
junit
4.12
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
- 在 application.yml 中添加数据源配置。
custom:
datasource:
first:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/first?characterEncoding=utf-8&useSSL=true
username: first_admin
password: 111111
second:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/second?characterEncoding=utf-8&useSSL=true
username: second_admin
password: 222222
third:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/third?characterEncoding=utf-8&useSSL=true
username: third_admin
password: 333333
- 编写数据源配置类。
7.1 first
数据源配置类:
package tutorial.spring.boot.data.source.config;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
public class FirstDataSourceConfig {
@Bean
@Primary
@ConfigurationProperties("custom.datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
public DataSource firstDataSource() {
return firstDataSourceProperties()
.initializeDataSourceBuilder()
.type(HikariDataSource.class)
.build();
}
@Bean
public JdbcOperations firstJdbcOperations() {
return new JdbcTemplate(firstDataSource());
}
@Bean
public DataSourceTransactionManager firstDataSourceTransactionManager() {
return new DataSourceTransactionManager(firstDataSource());
}
}
7.2 second
数据源配置类:
package tutorial.spring.boot.data.source.config;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
public class SecondDataSourceConfig {
@Bean
@ConfigurationProperties("custom.datasource.second")
public DataSourceProperties secondDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
public DataSource secondDataSource() {
return secondDataSourceProperties()
.initializeDataSourceBuilder()
.type(HikariDataSource.class)
.build();
}
@Bean
public JdbcOperations secondJdbcOperations() {
return new JdbcTemplate(secondDataSource());
}
@Bean
public DataSourceTransactionManager secondDataSourceTransactionManager() {
return new DataSourceTransactionManager(secondDataSource());
}
}
7.3 third
数据源配置类:
package tutorial.spring.boot.data.source.config;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
public class ThirdDataSourceConfig {
@Bean
@ConfigurationProperties("custom.datasource.third")
public DataSourceProperties thirdDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
public DataSource thirdDataSource() {
return thirdDataSourceProperties()
.initializeDataSourceBuilder()
.type(HikariDataSource.class)
.build();
}
@Bean
public JdbcOperations thirdJdbcOperations() {
return new JdbcTemplate(thirdDataSource());
}
@Bean
public DataSourceTransactionManager thirdDataSourceTransactionManager() {
return new DataSourceTransactionManager(thirdDataSource());
}
}
- 编写映射数据表的领域模型类。
8.1 映射 first
数据库 customer
表的领域模型类:
package tutorial.spring.boot.data.source.domain;
public class Customer {
/**
* 数据库表 customer 列名
*/
public static class ColumnConstant {
public static final String ID = "id";
public static final String NAME = "name";
public static final String PHONE_NUMBER = "phone_number";
}
private Long id;
private String name;
private String phoneNumber;
public Customer(String name, String phoneNumber) {
this.name = name;
this.phoneNumber = phoneNumber;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Customer customer = (Customer) o;
if (name != null ? !name.equals(customer.name) : customer.name != null) {
return false;
}
return phoneNumber != null ? phoneNumber.equals(customer.phoneNumber) : customer.phoneNumber == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (phoneNumber != null ? phoneNumber.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", phoneNumber='" + phoneNumber + '\'' +
'}';
}
}
8.2 映射 second
数据库 retailer
表的领域模型类:
package tutorial.spring.boot.data.source.domain;
public class Retailer {
/**
* 数据库表 retailer 列名
*/
public static class ColumnConstant {
public static final String ID = "id";
public static final String NAME = "name";
public static final String CONTACT = "contact";
}
private Long id;
private String name;
private String contact;
public Retailer(String name, String contact) {
this.name = name;
this.contact = contact;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Retailer retailer = (Retailer) o;
if (name != null ? !name.equals(retailer.name) : retailer.name != null) {
return false;
}
return contact != null ? contact.equals(retailer.contact) : retailer.contact == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (contact != null ? contact.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Retailer{" +
"id=" + id +
", name='" + name + '\'' +
", contact='" + contact + '\'' +
'}';
}
}
8.3 映射 third
数据库 factory
表的领域模型类:
package tutorial.spring.boot.data.source.domain;
public class Factory {
/**
* 数据库表 factory 列名
*/
public static class ColumnConstant {
public static final String ID = "id";
public static final String NAME = "name";
public static final String ADDRESS = "address";
}
private Long id;
private String name;
private String address;
public Factory(String name, String address) {
this.name = name;
this.address = address;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Factory factory = (Factory) o;
if (name != null ? !name.equals(factory.name) : factory.name != null) {
return false;
}
return address != null ? address.equals(factory.address) : factory.address == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (address != null ? address.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Factory{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
- 编写 DAO(Data Access Object)层接口。
9.1 访问 first
数据源 customer
表接口:
package tutorial.spring.boot.data.source.dao;
import tutorial.spring.boot.data.source.domain.Customer;
import java.sql.SQLException;
public interface ICustomerDao {
/**
* 新增客户
*
* @param customer 封装客户信息的Customer对象
* @return 插入记录主键
*/
long insert(Customer customer) throws SQLException;
/**
* 根据 ID 查询客户
*
* @param id 客户ID,对应主键
* @return 查询到的客户记录,如无对应记录则返回 null
*/
Customer select(long id);
}
9.2 访问 second
数据源 retailer
表接口:
package tutorial.spring.boot.data.source.dao;
import tutorial.spring.boot.data.source.domain.Retailer;
import java.sql.SQLException;
public interface IRetailerDao {
/**
* 新增零售商
*
* @param retailer 封装零售商信息的Retailer对象
* @return 插入记录主键
*/
long insert(Retailer retailer) throws SQLException;
/**
* 根据 ID 查询零售商
*
* @param id 零售商ID,对应主键
* @return 查询到的零售商记录,如无对应记录则返回 null
*/
Retailer select(long id);
}
9.3 访问 third
数据源 factory
表接口:
package tutorial.spring.boot.data.source.dao;
import tutorial.spring.boot.data.source.domain.Factory;
import java.sql.SQLException;
public interface IFactoryDao {
/**
* 新增工厂
*
* @param factory 封装工厂信息的Factory对象
* @return 插入记录主键
*/
long insert(Factory factory) throws SQLException;
/**
* 根据 ID 查询工厂
*
* @param id 工厂ID,对应主键
* @return 查询到的工厂记录,如无对应记录则返回 null
*/
Factory select(long id);
}
- 编写 DAO(Data Access Object)层实现。
10.1 访问 first
数据源 customer
表接口实现:
package tutorial.spring.boot.data.source.dao.impl;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import tutorial.spring.boot.data.source.dao.ICustomerDao;
import tutorial.spring.boot.data.source.domain.Customer;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Objects;
@Repository
public class CustomerDaoImpl implements ICustomerDao {
private final JdbcOperations jdbcOperations;
public CustomerDaoImpl(@Qualifier("firstJdbcOperations") JdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
}
@Override
public long insert(Customer customer) throws SQLException {
if (Objects.isNull(customer)) {
throw new IllegalArgumentException("Param[customer] is null!");
}
final String sql = "INSERT INTO customer ("
+ Customer.ColumnConstant.NAME + ", "
+ Customer.ColumnConstant.PHONE_NUMBER + ") VALUES (?, ?)";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcOperations.update(connection -> {
PreparedStatement preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, Objects.isNull(customer.getName()) ? "Anonymous Customer" : customer.getName());
preparedStatement.setString(2, Objects.isNull(customer.getPhoneNumber()) ? "" : customer.getPhoneNumber());
return preparedStatement;
}, keyHolder);
if (Objects.isNull(keyHolder.getKey())) {
throw new SQLException();
}
return keyHolder.getKey().longValue();
}
@Override
public Customer select(long id) {
String sql = "SELECT "
+ Customer.ColumnConstant.ID + ", "
+ Customer.ColumnConstant.NAME + ", "
+ Customer.ColumnConstant.PHONE_NUMBER
+ " FROM customer WHERE id=?";
List customers = jdbcOperations.query(sql, this::mapResultSetToCustomer, id);
return customers.size() == 0 ? null : customers.get(0);
}
private Customer mapResultSetToCustomer(ResultSet resultSet, int rowNum)
throws SQLException {
Customer customer = new Customer(resultSet.getString(Customer.ColumnConstant.NAME),
resultSet.getString(Customer.ColumnConstant.PHONE_NUMBER));
customer.setId(resultSet.getLong(Customer.ColumnConstant.ID));
return customer;
}
}
10.2 访问 second
数据源 retailer
表接口实现:
package tutorial.spring.boot.data.source.dao.impl;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import tutorial.spring.boot.data.source.dao.IRetailerDao;
import tutorial.spring.boot.data.source.domain.Retailer;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Objects;
@Repository
public class RetailerDaoImpl implements IRetailerDao {
private final JdbcOperations jdbcOperations;
public RetailerDaoImpl(@Qualifier("secondJdbcOperations") JdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
}
@Override
public long insert(Retailer retailer) throws SQLException {
if (Objects.isNull(retailer)) {
throw new IllegalArgumentException("Param[retailer] is null!");
}
final String sql = "INSERT INTO retailer ("
+ Retailer.ColumnConstant.NAME + ", "
+ Retailer.ColumnConstant.CONTACT + ") VALUES (?, ?)";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcOperations.update(connection -> {
PreparedStatement preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, Objects.isNull(retailer.getName()) ? "Anonymous Retailer" : retailer.getName());
preparedStatement.setString(2, Objects.isNull(retailer.getContact()) ? "" : retailer.getContact());
return preparedStatement;
}, keyHolder);
if (Objects.isNull(keyHolder.getKey())) {
throw new SQLException();
}
return keyHolder.getKey().longValue();
}
@Override
public Retailer select(long id) {
String sql = "SELECT "
+ Retailer.ColumnConstant.ID + ", "
+ Retailer.ColumnConstant.NAME + ", "
+ Retailer.ColumnConstant.CONTACT
+ " FROM retailer WHERE id=?";
List retailers = jdbcOperations.query(sql, this::mapResultSetToRetailer, id);
return retailers.size() == 0 ? null : retailers.get(0);
}
private Retailer mapResultSetToRetailer(ResultSet resultSet, int rowNum)
throws SQLException {
Retailer retailer = new Retailer(resultSet.getString(Retailer.ColumnConstant.NAME),
resultSet.getString(Retailer.ColumnConstant.CONTACT));
retailer.setId(resultSet.getLong(Retailer.ColumnConstant.ID));
return retailer;
}
}
10.3 访问 third
数据源 factory
表接口实现:
package tutorial.spring.boot.data.source.dao.impl;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import tutorial.spring.boot.data.source.dao.IFactoryDao;
import tutorial.spring.boot.data.source.domain.Factory;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Objects;
@Repository
public class FactoryDaoImpl implements IFactoryDao {
private final JdbcOperations jdbcOperations;
public FactoryDaoImpl(@Qualifier("thirdJdbcOperations") JdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
}
@Override
public long insert(Factory factory) throws SQLException {
if (Objects.isNull(factory)) {
throw new IllegalArgumentException("Param[factory] is null!");
}
final String sql = "INSERT INTO factory ("
+ Factory.ColumnConstant.NAME + ", "
+ Factory.ColumnConstant.ADDRESS + ") VALUES (?, ?)";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcOperations.update(connection -> {
PreparedStatement preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, Objects.isNull(factory.getName()) ? "Anonymous Factory" : factory.getName());
preparedStatement.setString(2, Objects.isNull(factory.getAddress()) ? "" : factory.getAddress());
return preparedStatement;
}, keyHolder);
if (Objects.isNull(keyHolder.getKey())) {
throw new SQLException();
}
return keyHolder.getKey().longValue();
}
@Override
public Factory select(long id) {
String sql = "SELECT "
+ Factory.ColumnConstant.ID + ", "
+ Factory.ColumnConstant.NAME + ", "
+ Factory.ColumnConstant.ADDRESS
+ " FROM factory WHERE id=?";
List factories = jdbcOperations.query(sql, this::mapResultSetToFactory, id);
return factories.size() == 0 ? null : factories.get(0);
}
private Factory mapResultSetToFactory(ResultSet resultSet, int rowNum)
throws SQLException {
Factory factory = new Factory(resultSet.getString(Factory.ColumnConstant.NAME),
resultSet.getString(Factory.ColumnConstant.ADDRESS));
factory.setId(resultSet.getLong(Factory.ColumnConstant.ID));
return factory;
}
}
- 编写单元测试。
11.1 测试访问 first
数据源 customer
表:
package tutorial.spring.boot.data.source.dao;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import tutorial.spring.boot.data.source.domain.Customer;
import java.sql.SQLException;
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional("firstDataSourceTransactionManager")
public class CustomerDaoTest {
@Autowired
private ICustomerDao customerDao;
@Test
public void test() throws SQLException {
Assert.assertNotNull(customerDao);
Customer customer = new Customer("Tommy", "214-110-256");
long id = customerDao.insert(customer);
Assert.assertTrue(id > 0);
Customer result = customerDao.select(id);
Assert.assertEquals(customer, result);
}
}
11.2 测试访问 second
数据源 retailer
表:
package tutorial.spring.boot.data.source.dao;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import tutorial.spring.boot.data.source.domain.Retailer;
import java.sql.SQLException;
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional("secondDataSourceTransactionManager")
public class RetailerDaoTest {
@Autowired
private IRetailerDao retailerDao;
@Test
public void test() throws SQLException {
Assert.assertNotNull(retailerDao);
Retailer retailer = new Retailer("Costco", "210-111-111");
long id = retailerDao.insert(retailer);
Assert.assertTrue(id > 0);
Retailer result = retailerDao.select(id);
Assert.assertEquals(retailer, result);
}
}
11.3 测试访问 third
数据源 factory
表:
package tutorial.spring.boot.data.source.dao;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import tutorial.spring.boot.data.source.domain.Factory;
import java.sql.SQLException;
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional("thirdDataSourceTransactionManager")
public class FactoryDaoTest {
@Autowired
private IFactoryDao factoryDao;
@Test
public void test() throws SQLException {
Assert.assertNotNull(factoryDao);
Factory factory = new Factory("Valued", "Texas");
long id = factoryDao.insert(factory);
Assert.assertTrue(id > 0);
Factory result = factoryDao.select(id);
Assert.assertEquals(factory, result);
}
}
执行过程略。
总结
注意:
- 配置多个数据源时必须指定其中一个用
@Primary
注解; - 不同的数据源可以指定不同的数据库类型和不同的连接池,本文只演示了连接
MySQL
数据库和使用 Spring Boot 默认使用的HikariCP
连接池; - 不同的数据源需要指定不同的事务管理器
DataSourceTransactionManager
,否则默认的事务管理器只对注解为@Primary
的数据源生效。