0%

Java 多数据源demo

环境

使用 spring boot 2.1.4,mybatis,druid 框架 构建.数据库为mysql5.7

测试demo

详细的代码配置请从github 下载查看

配置文件

如下,根据druid 的文档以及,spring boot2 变更,属性无法继承导致,每个数据源需要配置一份.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//application.yml
datasource:
druid:
filter:
stat:
enabled: true
wall:
config:
none-base-statement-allow: true #是否允许执行非基本语句
multi-statement-allow: true #是否允许执行多个语句
enabled: true
config:
enabled: true
log4j2:
enabled: true
statement-executable-sql-log-enable: true
db1:
db-type: mysql
driver-class-name: com.mysql.jdbc.Driver
max-active: 200 #连接池最大值
initial-size: 10 # 初始化大小
max-wait: 30000 #获取连接最大等待时间
min-idle: 10 #连接池最小空闲
time-between-eviction-runs-millis: 30000 #逐出连接的检测时间间隔
min-evictable-idle-time-millis: 30000 #最小逐出时间
validation-query: SELECT 1 #检测连接是否有效的SQL
testWhileIdle: true #申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效
testOnBorrow: false #借出连接时是否做测试
testOnReturn: true #归还连接时是否做测试
removeAbandoned: true #超过时间限制是否回收
removeAbandonedTimeout: 3600 # 超过时间限制多长
max-pool-prepared-statement-per-connection-size: 50 #启用PSCache
db2:
db-type: mysql
driver-class-name: com.mysql.jdbc.Driver
max-active: 200 #连接池最大值
initial-size: 10 # 初始化大小
max-wait: 30000 #获取连接最大等待时间
min-idle: 10 #连接池最小空闲
time-between-eviction-runs-millis: 30000 #逐出连接的检测时间间隔
min-evictable-idle-time-millis: 30000 #最小逐出时间
validation-query: SELECT 1 #检测连接是否有效的SQL
testWhileIdle: true #申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效
testOnBorrow: false #借出连接时是否做测试
testOnReturn: true #归还连接时是否做测试
removeAbandoned: true #超过时间限制是否回收
removeAbandonedTimeout: 3600 # 超过时间限制多长
max-pool-prepared-statement-per-connection-size: 50 #启用PSCache
1
2
3
4
5
6
7
8
9
10
11
12
application-dev.yml
druid:
db1:
name: db1
url: jdbc:mysql://192.168.50.100:3306/db1?allowMultiQueries=true&autoReconnect=true&useUnicode=true&characterEncoding=utf-8
username: db1
password: 123456
db2:
name: db2
url: jdbc:mysql://192.168.50.100:3306/db2?allowMultiQueries=true&autoReconnect=true&useUnicode=true&characterEncoding=utf-8
username: db2
password: 123456

在单数据源项目中,我们使用 spring boot 以及 相关的mybatis starter 我们使用配置文件即可 自动配置相关的对象
但是在多数据源项目中 ,目前 我们需要将配置文件中 关于mybatis 的项目手动注入到 相关的对象中
例如 以下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mybatis:
# mybatis config 其他配置 需要到 SqlSessionFactoryBean 中 手动配置
configuration:
cache-enabled: true #全局映射器启用缓存
multiple-result-sets-enabled: true #对于未知的SQL查询,允许返回不同的结果集以达到通用的效果
use-column-label: true #允许使用列标签代替列名
use-generated-keys: false #不允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 -
auto-mapping-behavior: partial #给予被嵌套的resultMap以字段-属性的映射支持 FULL,PARTIAL
safe-row-bounds-enabled: false #允许在嵌套语句上使用RowBounds
mapUnderscoreToCamelCase: true #自动映射
localCacheScope: session #缓存会话范围
jdbcTypeForNull: other #当没有特定的JDBC类型时,指定空值的JDBC类型为参数提供了。 某些驱动程序需要指定列JDBC类型但其他类型使用泛型值,如NULL,VARCHAR或OTHER
lazyLoadTriggerMethods: equals,clone,hashCode,toString #指定哪个Object的方法触发延迟加载
aggressive-lazy-loading: false # 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指 定),不会加载关联表的所有字段,以提高性能

将配置 注入到sqlSessionFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private final MybatisProperties myBatisProperties;
//或者配置文件中的 属性
public DB1DataSourceConfig(
MybatisProperties myBatisProperties) {
this.myBatisProperties = myBatisProperties;
}

@Bean(name = "db1SqlSessionFactory")
public SqlSessionFactory db1SqlSessionFactory(
@Qualifier("db1DataSource") DataSource db1DataSource)
throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(db1DataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources(DB1DataSourceConfig.MAPPER_LOCATION));
//sessionFactory.setTypeAliasesPackage("com.xx.po");
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session
.Configuration();
if (myBatisProperties.getConfiguration() != null) {
BeanUtils.copyProperties(myBatisProperties.getConfiguration(), configuration);
}
sessionFactory.setConfiguration(configuration);
return sessionFactory.getObject();
}

仍然存在一些问题:

  1. mybatis 中其他一些配置 硬编码在代码中 例如TypeAliasesPackage
  2. 某些属性的变动仍然需要 修改代码 才能生效

多数据源与单数据源的对比

单数据源:

  1. 配置简单
  2. 事务管理清晰

多数据源:

  1. 配置繁琐 ,每一个数据源都需要重复 DataSource,DataSourceTransactionManager,SqlSessionFactory
  2. 每个事务管理 都需要指定对应的SqlSessionFactory
  3. 多个数据源事务 无法嵌套提交,一致性的问题 可参加 分布式事务的 最终一致性 相关的解决方法

总结

查询相关资料中,对于多数据源配置 做了一些总结,希望有所帮助
在demo 中,有简单的事务测试,例如多数据源嵌套提交会产生java.lang.IllegalStateException: Transaction synchronization 的问题.
以及多数据源提交的规则.
至于如何解决一致性问题是另外一个比较大的问题.

其他实现

spring 有相关动态数据源切换的方案, 可用 google 搜索相关文档

参考链接

以下参考链接由于当时未记录,只显示当前链接

github kazuki43zoo

github mybatis issues