Skip to content

Commit 701496a

Browse files
committed
添加ApiBoot DataSource Switch 示例.
1 parent da26a58 commit 701496a

File tree

4 files changed

+320
-0
lines changed

4 files changed

+320
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- **文档自动生成**:通过集成`Swagger2`来完成文档的侵入式生成,侵入式文档后期会被替代,`ApiBoot Security Oauth`已默认排除`swagger2`相关的资源路径。
1616
- **返回JSON格式化**:使用阿里巴巴的`FastJson`来完成返回`Json`字符串的格式化,自动扫描装载自定义的`ValueFilter`实现类,用于自定义返回格式化。
1717
- **数据库ORM框架**`mybatis-enhance`是一款由我开源的数据库持久化框架,基于`mybatis`进行封装编写,可以完成动态查询数据,语法与`SQL`语法几乎一致,内置常用方法提供直接调用,支持方法命名规则查询,一个接口方法就可以自动完成查询,不再编写`SQL`语句。
18+
- **动态数据源**:完成项目的多数据源配置、内部集成`druid``HikariCP`数据源实现方式,配置主从数据源、多数据库类型数据源、多种数据源实现方式集成。
1819
- **自动分页插件**`mybatis-pageable`是一款由我开源的自动化分页插件,直接摆脱编写`分页代码`,仅仅需要传递的分页参数就可以自动进行查询,目前支持主流的**12**种数据库。
1920
- **代码生成插件**`code-builder`是一款由我开源的代码生成插件,直接摆脱实体类的生成,支持自定义`freemarker`模板来完成自定义生成类文件,比如:`Service``Controller``Mapper`等。
2021
- **七牛云资源处理**:集成七牛云提供的SDK来完成文件的上传、下载等方法实现,开箱即用。
@@ -31,6 +32,7 @@
3132
- **[Quartz](http://www.quartz-scheduler.org)**:分布式定时任务调度框架
3233
- **[Swagger2](https://swagger.io/)**:Swagger是一款API文档生成工具,自动扫描代码进行生成可运行测试的文档。
3334
- **[Mybatis Enhance](https://github.com/hengboy/mybatis-enhance)**`Enhance`是对于原生的`MyBatis`的增强编写,不影响任何原生的使用,使用后完全替代`mybatis-core``mybatis-spring`以及`mybatis-spring-boot-starter`,可以使用`SpringBoot`配置文件的形式进行配置相关的内容,尽可能强大的方便快速的集成`MyBatis`
35+
- **[DataSource Switch](https://github.com/hengboy/api-boot/tree/master/api-boot-project/api-boot-plugins/api-boot-plugin-datasource-switch)**:一款多数据源自动切换框架,可配置多种数据库类型数据源集成、主从数据源配置。
3436
- **[Mybatis Pageable](https://github.com/hengboy/mybatis-pageable)**`MyBatis-Pageable`是一款自动化分页的插件,基于`MyBatis`内部的插件`Interceptor`拦截器编写完成,拦截`Executor.query`的两个重载方法计算出分页的信息以及根据配置的数据库`Dialect`自动执行不同的查询语句完成总数量的统计。
3537
- **[Code Builder](https://github.com/hengboy/code-builder)**`code-builder`是一款代码生成`maven mojo`插件,通过简单的配置就可以完成数据库内`Table`转换`Entity`或者其他实体类,想怎么生成完全根据你的个人业务逻辑,`code-builder`尽可能的完善的提供数据库内的一些定义的信息,让你更方便更灵活的来生成`Java`文件。
3638

@@ -72,6 +74,7 @@ Demo列表:
7274
- [ApiBoot Alibaba OSS](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-alibaba-oss)
7375
- [ApiBoot Alibaba SMS](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-alibaba-sms)
7476
- [ApiBoot Quartz](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-quartz)
77+
- [ApiBoot DataSource Switch](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-datasource-switch)
7578

7679
## 版本管理规范
7780

@@ -112,6 +115,7 @@ yuqiyu999
112115
│ ├── api-boot-sample-alibaba-oss
113116
│ ├── api-boot-sample-alibaba-sms
114117
│ ├── api-boot-sample-http-converter
118+
│ ├── api-boot-sample-datasource-switch
115119
│ ├── api-boot-sample-security-oauth-jwt
116120
│ ├── api-boot-sample-quartz
117121
│ └── api-boot-sample-swagger

api-boot-project/api-boot-starters/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ApiBoot`提供的所有封装依赖对应第三方框架关系如下所示:
1111
| [api-boot-starter-alibaba-oss](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-alibaba-oss) | 集成阿里云Oss对象存储接口服务 |
1212
| [api-boot-starter-alibaba-sms](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-alibaba-sms) | 集成阿里云国际短信接口服务 |
1313
| [api-boot-starter-quartz](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-quartz) | 集成分布式定时任务框架Quartz |
14+
| [api-boot-starter-datasource-switch](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-datasource-switch) | 集成支持多数据源自动切换、动态创建数据源 |
1415

1516

1617

api-boot-samples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ Demo列表:
88
- [ApiBoot Alibaba OSS](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-alibaba-oss)
99
- [ApiBoot Alibaba SMS](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-alibaba-sms)
1010
- [ApiBoot Quartz](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-quartz)
11+
- [ApiBoot DataSource Switch](https://github.com/hengboy/api-boot/tree/master/api-boot-samples/api-boot-sample-datasource-switch)
1112

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
## ApiBoot DataSource Switch
2+
3+
顾名思义,`DataSource Switch`是用于数据源选择切换的框架,这是一款基于`Spring AOP`切面指定注解实现的,通过简单的数据源注解配置就可以完成访问时的自动切换,`DataSource Switch`切换过程中是线程安全的。
4+
5+
### 添加依赖
6+
7+
使用`DataSource Switch`很简单,在`pom.xml`配置文件内添加如下依赖:
8+
9+
```xml
10+
<!--ApiBoot DataSource Switch-->
11+
<dependency>
12+
<groupId>org.minbox.framework</groupId>
13+
<artifactId>api-boot-starter-datasource-switch</artifactId>
14+
</dependency>
15+
```
16+
`ApiBoot`所提供的依赖都不需要添加版本号,具体查看[ApiBoot版本依赖](https://github.com/hengboy/api-boot/blob/master/README.md#%E6%B7%BB%E5%8A%A0%E7%89%88%E6%9C%AC%E4%BE%9D%E8%B5%96)
17+
18+
### 集成数据源实现
19+
20+
目前`ApiBoot DataSource Switch`集成了`Druid``HikariCP`两种数据源实现依赖,在使用方面也有一定的差异,因为每一个数据源的内置参数不一致。
21+
22+
- `Druid`:参数配置前缀为`api.boot.datasource.druid`
23+
- `HikariCP`:参数配置前缀为`api.boot.datasource.hikari`
24+
25+
**具体使用请查看下面功能配置介绍。**
26+
27+
28+
29+
### 配置参数
30+
31+
| 参数名 | 参数默认值 | 是否必填 | 参数描述 |
32+
| --------------------------------------------------------- | ------------------------ | -------- | ------------------------------------------------------------ |
33+
| `api.boot.datasource.primary` | master || 主数据源名称 |
34+
| `api.boot.datasource.druid.{poolName}.url` ||| 数据库连接字符串 |
35+
| `api.boot.datasource.druid.{poolName}.username` ||| 用户名 |
36+
| `api.boot.datasource.druid.{poolName}.password` ||| 密码 |
37+
| `api.boot.datasource.druid.{poolName}.driver-class-name` | com.mysql.cj.jdbc.Driver || 驱动类型 |
38+
| `api.boot.datasource.druid.{poolName}.filters` | stat,wall,slf4j || Druid过滤 |
39+
| `api.boot.datasource.druid.{poolName}.max-active` | 20 || 最大连接数 |
40+
| `api.boot.datasource.druid.{poolName}.initial-size` | 1 || 初始化连接数 |
41+
| `api.boot.datasource.druid.{poolName}.max-wait` | 60000 || 最大等待市场,单位:毫秒 |
42+
| `api.boot.datasource.druid.{poolName}.validation-query` | select 1 from dual || 检查sql |
43+
| `api.boot.datasource.druid.{poolName}.test-while-idle` | true || 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 |
44+
| `api.boot.datasource.druid.{poolName}.test-on-borrow` | false || 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
45+
| `api.boot.datasource.druid.{poolName}.test-on-return` | false || 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
46+
| `api.boot.datasource.hikari.{poolName}.url` ||| 数据库连接字符串 |
47+
| `api.boot.datasource.hikari.{poolName}.username` ||| 用户名 |
48+
| `api.boot.datasource.hikari.{poolName}.password` ||| 密码 |
49+
| `api.boot.datasource.hikari.{poolName}.driver-class-name` | com.mysql.cj.jdbc.Driver || 数据库驱动类全限定名 |
50+
| `api.boot.datasource.hikari.{poolName}.property` ||| HikariCP属性配置 |
51+
52+
`HikariCP`数据源是`SpringBoot2.x`自带的,配置参数请访问[HikariCP](https://github.com/brettwooldridge/HikariCP)
53+
54+
### 单主配置
55+
56+
`ApiBoot DataSource Switch`支持单主数据源的配置,`application.yml`配置文件如下所示:
57+
58+
```yaml
59+
api:
60+
boot:
61+
datasource:
62+
# 配置使用hikari数据源
63+
hikari:
64+
# master datasource config
65+
master:
66+
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=Asia/Shanghai
67+
username: root
68+
password: 123456
69+
```
70+
71+
### 修改主数据源名称
72+
73+
`master`为默认的主数据源的`poolName`,这里可以进行修改为其他值,不过需要对应修改`primary`参数,如下所示:
74+
75+
```yaml
76+
api:
77+
boot:
78+
datasource:
79+
# 主数据源,默认值为master
80+
primary: main
81+
# 配置使用hikari数据源
82+
hikari:
83+
# master datasource config
84+
main:
85+
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=Asia/Shanghai
86+
username: root
87+
password: 123456
88+
```
89+
90+
在上面配置主数据源的`poolName`修改为`main`。
91+
92+
### 主从配置
93+
94+
如果你的项目内存在`单主单从`、`一主多从`的配置方式,如下所示:
95+
96+
```yaml
97+
api:
98+
boot:
99+
datasource:
100+
# 配置使用hikari数据源
101+
hikari:
102+
# master datasource config
103+
master:
104+
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=Asia/Shanghai
105+
username: root
106+
password: 123456
107+
# 默认值为【com.mysql.cj.jdbc.Driver】
108+
#driver-class-name: com.mysql.cj.jdbc.Driver
109+
# slave 1
110+
slave_1:
111+
url: jdbc:mysql://localhost:3306/oauth2?characterEncoding=utf8&serverTimezone=Asia/Shanghai
112+
username: root
113+
password: 123456
114+
# slave 2
115+
slave_2:
116+
url: jdbc:mysql://localhost:3306/resources?characterEncoding=utf8&serverTimezone=Asia/Shanghai
117+
username: root
118+
password: 123456
119+
```
120+
121+
在上面是`一主多从`的配置方式,分别是`master`、`slave_1`、`slave_2`。
122+
123+
### 多类型数据库配置
124+
125+
`ApiBoot DataSource Switch`提供了一个项目内连接多个不同类型的数据库,如:`MySQL`、`Oracle`...等,如下所示:
126+
127+
```yaml
128+
api:
129+
boot:
130+
# 主数据源,默认值为master
131+
primary: mysql
132+
hikari:
133+
mysql:
134+
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=Asia/Shanghai
135+
username: root
136+
password: 123456
137+
oracle:
138+
url: jdbc:oracle:thin:@172.16.10.25:1521:torcl
139+
username: root
140+
password: 123456
141+
driver-class-name: oracle.jdbc.driver.OracleDriver
142+
```
143+
144+
在上面配置中,`master`主数据源使用的`MySQL`驱动连接`MySQL`数据库,而`slave`从数据源则是使用的`Oracle`驱动连接的`Oracle`数据库。
145+
146+
### 动态创建数据源
147+
148+
`ApiBoot DataSource Switch`内部提供了动态创建数据源的方法,可以通过注入`ApiBootDataSourceFactoryBean`来进行添加,如下所示:
149+
150+
```java
151+
@Autowired
152+
private ApiBootDataSourceFactoryBean factoryBean;
153+
154+
public void createNewDataSource() throws Exception {
155+
// 创建Hikari数据源
156+
// 如果创建Druid数据源,使用DataSourceDruidConfig
157+
DataSourceHikariConfig config = new DataSourceHikariConfig();
158+
// 数据库连接:必填
159+
config.setUrl("jdbc:mysql://localhost:3306/resources");
160+
// 用户名:必填
161+
config.setUsername("root");
162+
// 密码:必填
163+
config.setPassword("123456");
164+
// 数据源名称:必填(用于@DataSourceSwitch注解value值使用)
165+
config.setPoolName("dynamic");
166+
167+
// 创建数据源
168+
DataSource dataSource = factoryBean.newDataSource(config);
169+
Connection connection = dataSource.getConnection();
170+
System.out.println(connection.getCatalog());
171+
connection.close();
172+
}
173+
```
174+
175+
### 自动切换
176+
177+
`ApiBoot DataSource Switch`的数据源自动切换主要归功于`Spring`的`AOP`,通过切面`@DataSourceSwitch`注解,获取注解配置的`value`值进行设置当前线程所用的数据源名称,从而通过`AbstractRoutingDataSource`进行数据源的路由切换。
178+
179+
我们沿用上面**一主多从**的配置进行代码演示,配置文件`application.yml`参考上面配置,代码示例如下:
180+
181+
#### 从数据源示例类
182+
183+
```java
184+
@Service
185+
@DataSourceSwitch("slave")
186+
public class SlaveDataSourceSampleService {
187+
/**
188+
* DataSource Instance
189+
*/
190+
@Autowired
191+
private DataSource dataSource;
192+
193+
/**
194+
* 演示输出数据源的catalog
195+
*
196+
* @throws Exception
197+
*/
198+
public void print() throws Exception {
199+
// 获取链接
200+
Connection connection = dataSource.getConnection();
201+
// 输出catalog
202+
System.out.println(this.getClass().getSimpleName() + " ->" + connection.getCatalog());
203+
// 关闭链接
204+
connection.close();
205+
}
206+
}
207+
```
208+
209+
#### 主数据源示例类
210+
211+
```java
212+
@Service
213+
@DataSourceSwitch("master")
214+
public class MasterDataSourceSampleService {
215+
/**
216+
* DataSource Instance
217+
*/
218+
@Autowired
219+
private DataSource dataSource;
220+
/**
221+
* Slave Sample Service
222+
*/
223+
@Autowired
224+
private SlaveDataSourceSampleService slaveDataSourceSampleService;
225+
226+
/**
227+
* 演示输出主数据源catalog
228+
* 调用从数据源类演示输出catalog
229+
*
230+
* @throws Exception
231+
*/
232+
public void print() throws Exception {
233+
Connection connection = dataSource.getConnection();
234+
System.out.println(this.getClass().getSimpleName() + " ->" + connection.getCatalog());
235+
connection.close();
236+
slaveDataSourceSampleService.print();
237+
}
238+
}
239+
```
240+
241+
- 在`主数据源`的示例类内,我们通过`@DataSourceSwitch("master")`注解的`value`进行定位连接`master`数据源数据库。
242+
- 同样在`从数据库`的示例类内,我们也可以通过`@DataSourceSwitch("slave")`注解的`value`进行定位连接`slave`数据源数据库。
243+
244+
#### 单元测试示例
245+
246+
在上面的测试示例中,我们使用交叉的方式进行验证`数据源路由`是否可以正确的进行切换,可以编写一个单元测试进行验证结果,如下所示:
247+
248+
```java
249+
@Autowired
250+
private MasterDataSourceSampleService masterDataSourceSampleService;
251+
@Test
252+
public void contextLoads() throws Exception {
253+
masterDataSourceSampleService.print();
254+
}
255+
```
256+
257+
运行上面测试方法,结果如下所示:
258+
259+
```sh
260+
MasterDataSourceSampleService ->test
261+
2019-04-04 10:20:45.407 INFO 7295 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Starting...
262+
2019-04-04 10:20:45.411 INFO 7295 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Start completed.
263+
SlaveDataSourceSampleService ->oauth2
264+
```
265+
266+
单次执行数据源切换没有任何的问题,`master`数据源获取`catalog`输出后,调用`slave`示例类进行输出`catalog`。
267+
268+
> `ApiBoot DataSource Switch`会在项目启动时首先初始化`master`节点`DataSource`实例,其他实例会在第一次调用时进行初始化。
269+
270+
### 压力性能测试
271+
272+
单次执行单线程操作没有问题,不代表多线程下不会出现问题,在开头说到过`ApiBoot DataSource Switch`是线程安全的,所以接下来我们来验证这一点,我们需要添加压力测试的依赖,如下所示:
273+
274+
```xml
275+
<dependency>
276+
<groupId>org.databene</groupId>
277+
<artifactId>contiperf</artifactId>
278+
<version>2.3.4</version>
279+
<scope>test</scope>
280+
</dependency>
281+
```
282+
283+
接下来把上面的单元测试代码改造下,如下所示:
284+
285+
```java
286+
// 初始化压力性能测试对象
287+
@Rule
288+
public ContiPerfRule i = new ContiPerfRule();
289+
290+
@Autowired
291+
private MasterDataSourceSampleService masterDataSourceSampleService;
292+
/**
293+
* 开启500个线程执行10000次
294+
*/
295+
@Test
296+
@PerfTest(invocations = 10000, threads = 500)
297+
public void contextLoads() throws Exception {
298+
masterDataSourceSampleService.print();
299+
}
300+
```
301+
302+
> 测试环境:
303+
>
304+
> 硬件:i7、16G、256SSD
305+
>
306+
> 系统:OS X
307+
>
308+
> 整个过程大约是10秒左右,`ApiBoot DataSource Switch`并没有发生出现切换错乱的情况。
309+
310+
### 注意事项
311+
312+
1. 在使用`ApiBoot DataSource Switch`时需要添加对应数据库的依赖
313+
2. 如果使用`Druid`连接池,不要配置使用`druid-starter`的依赖,请使用`druid`依赖。
314+
3. 配置`poolName`时不要添加特殊字符、中文、中横线等。

0 commit comments

Comments
 (0)