使用DataSource Switch
很简单,在pom.xml
配置文件内添加如下依赖:
ApiBoot
所提供的依赖都不需要添加版本号,具体查看
集成数据源实现
目前ApiBoot DataSource Switch
集成了Druid
、HikariCP
两种数据源实现依赖,在使用方面也有一定的差异,因为每一个数据源的内置参数不一致。
Druid
:参数配置前缀为api.boot.datasource.druid
HikariCP
:参数配置前缀为api.boot.datasource.hikari
具体使用请查看下面功能配置介绍。
配置参数
HikariCP
数据源是SpringBoot2.x
自带的,配置参数请访问HikariCP。
ApiBoot DataSource Switch
支持单主数据源的配置,application.yml
配置文件如下所示:
- api:
- boot:
- datasource:
- # 配置使用hikari数据源
- hikari:
- # master datasource config
- master:
- url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=Asia/Shanghai
- username: root
- password: 123456
修改主数据源名称
master
为默认的主数据源的poolName
,这里可以进行修改为其他值,不过需要对应修改primary
参数,如下所示:
- api:
- boot:
- datasource:
- # 主数据源,默认值为master
- primary: main
- # 配置使用hikari数据源
- hikari:
- # main datasource config
- main:
- url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=Asia/Shanghai
- username: root
- password: 123456
在上面配置主数据源的poolName
修改为main
。
主从配置
如果你的项目内存在单主单从
、一主多从
的配置方式,如下所示:
- api:
- boot:
- datasource:
- # 配置使用hikari数据源
- hikari:
- # master datasource config
- master:
- url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=Asia/Shanghai
- username: root
- password: 123456
- # 默认值为【com.mysql.cj.jdbc.Driver】
- #driver-class-name: com.mysql.cj.jdbc.Driver
- # slave 1 datasource config
- slave_1:
- username: root
- password: 123456
- # slave 2 datasource config
- slave_2:
- url: jdbc:mysql://localhost:3306/resources?characterEncoding=utf8&serverTimezone=Asia/Shanghai
- username: root
- password: 123456
在上面是一主多从
的配置方式,分别是master
、slave_1
、slave_2
。
ApiBoot DataSource Switch
提供了一个项目内连接多个不同类型的数据库,如:MySQL
、Oracle
…等,如下所示:
在上面配置中,master
主数据源使用的MySQL
驱动连接MySQL
数据库,而slave
从数据源则是使用的Oracle
驱动连接的Oracle
数据库。
动态创建数据源
ApiBoot DataSource Switch
内部提供了动态创建数据源的方法,可以通过注入ApiBootDataSourceFactoryBean
来进行添加,如下所示:
- @Autowired
- private ApiBootDataSourceFactoryBean factoryBean;
public void createNewDataSource() throws Exception {
// 如果创建Druid数据源,使用DataSourceDruidConfig
DataSourceHikariConfig config = new DataSourceHikariConfig();
// 数据库连接:必填
config.setUrl("jdbc:mysql://localhost:3306/resources");
// 用户名:必填
config.setUsername("root");
// 密码:必填
config.setPassword("123456");
// 数据源名称:必填(用于@DataSourceSwitch注解value值使用)
config.setPoolName("dynamic");
// 创建数据源
DataSource dataSource = factoryBean.newDataSource(config);
Connection connection = dataSource.getConnection();
System.out.println(connection.getCatalog());
connection.close();
自动切换
ApiBoot DataSource Switch
的数据源自动切换主要归功于的AOP
,通过切面@DataSourceSwitch
注解,获取注解配置的value
值进行设置当前线程所用的数据源名称,从而通过AbstractRoutingDataSource
进行数据源的路由切换。
我们沿用上面一主多从的配置进行代码演示,配置文件application.yml
参考上面配置,代码示例如下:
从数据源示例类
- @Service
- @DataSourceSwitch("slave")
- public class SlaveDataSourceSampleService {
- /**
- * DataSource Instance
- */
- @Autowired
- private DataSource dataSource;
- /**
- * 演示输出数据源的catalog
- *
- * @throws Exception
- */
- public void print() throws Exception {
- // 获取链接
- Connection connection = dataSource.getConnection();
- // 输出catalog
- System.out.println(this.getClass().getSimpleName() + " ->" + connection.getCatalog());
- // 关闭链接
- connection.close();
- }
- }
主数据源示例类
- @Service
- @DataSourceSwitch("master")
- /**
- * DataSource Instance
- */
- @Autowired
- private DataSource dataSource;
- /**
- * Slave Sample Service
- */
- @Autowired
- private SlaveDataSourceSampleService slaveDataSourceSampleService;
- /**
- * 演示输出主数据源catalog
- * 调用从数据源类演示输出catalog
- *
- * @throws Exception
- */
- public void print() throws Exception {
- Connection connection = dataSource.getConnection();
- System.out.println(this.getClass().getSimpleName() + " ->" + connection.getCatalog());
- connection.close();
- slaveDataSourceSampleService.print();
- }
- }
- 在
主数据源
的示例类内,我们通过@DataSourceSwitch("master")
注解的value
进行定位连接master
数据源数据库。 - 同样在
从数据库
的示例类内,我们也可以通过@DataSourceSwitch("slave")
注解的value
进行定位连接slave
数据源数据库。
单元测试示例
在上面的测试示例中,我们使用交叉的方式进行验证数据源路由
是否可以正确的进行切换,可以编写一个单元测试进行验证结果,如下所示:
运行上面测试方法,结果如下所示:
- MasterDataSourceSampleService ->test
- 2019-04-04 10:20:45.407 INFO 7295 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Starting...
- 2019-04-04 10:20:45.411 INFO 7295 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Start completed.
- SlaveDataSourceSampleService ->oauth2
单次执行数据源切换没有任何的问题,master
数据源获取catalog
输出后,调用slave
示例类进行输出catalog
。
单次执行单线程操作没有问题,不代表多线程下不会出现问题,在开头说到过ApiBoot DataSource Switch
是线程安全的,所以接下来我们来验证这一点,我们需要添加压力测试的依赖,如下所示:
- <dependency>
- <groupId>org.databene</groupId>
- <artifactId>contiperf</artifactId>
- <version>2.3.4</version>
- <scope>test</scope>
- </dependency>
接下来把上面的单元测试代码改造下,如下所示:
- // 初始化压力性能测试对象
- @Rule
- public ContiPerfRule i = new ContiPerfRule();
- @Autowired
- private MasterDataSourceSampleService masterDataSourceSampleService;
- /**
- * 开启500个线程执行10000次
- */
- @Test
- @PerfTest(invocations = 10000, threads = 500)
- public void contextLoads() throws Exception {
- masterDataSourceSampleService.print();
- }
测试环境:
硬件:i7、16G、256SSD
系统:OS X
整个过程大约是10秒左右,
ApiBoot DataSource Switch
并没有发生出现切换错乱的情况。
注意事项
- 在使用
ApiBoot DataSource Switch
时需要添加对应数据库的依赖 - 如果使用
Druid
连接池,不要配置使用druid-starter
的依赖,请使用druid
依赖。