spring-boot的自动化配置中是包含数据源连接配置的。但有些时候我们需要自定义数据源连接的配置,比如:
- 使用的数据库连接池Spring暂时还不支持;
- 需要配置连接多数据源;
- 需要自定义一些数据库连接配置项。
这三种只是我曾经遇到的情形,当然还有些其他的情形。接下来就以曾经遇到的一个问题进行展开。
自定义数据源
我们在生产环境使用的数据库连接池是alibaba的druid。数据库连接配置大致是这样的:
1 2 3 4 5 |
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.h2.Driver url: jdbc:h2:mem:worker |
这里我用h2的内存数据库做个演示。在启动的时候会遇到一个错误日志:
1 |
2019-09-08 17:11:15.129 ERROR 2088 --- [ main] com.alibaba.druid.pool.DruidDataSource : testWhileIdle is true, validationQuery not set |
解决这个错误的方法按理来说是很简单,只需要在数据库的配置中添加一行validation-query
就好了:
1 |
validation-query: select 1 |
不过不幸的是SpringBoot目前的版本(2.1.7.RELEASE)中的数据库连接自动化配置中没有validation-query
选项,也不支持druid数据库连接池的自动化配置。
要解决这个问题,自定义Druid的自动化配置当然是一个好办法;另一个较为简单些的办法就是使用自定义数据源连接配置了。
首先,修改下项目配置:
1 2 3 4 5 6 7 8 9 10 11 |
spring: application: name: spring-boot-database custom: datasource: worker: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.h2.Driver url: jdbc:h2:mem:worker validation-query: select 1 |
为了避免因自动化配置产生干扰,这里将数据库连接配置移动到了custom下。
然后,创建一个数据库连接配置类:
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 |
@Configuration @MapperScan(basePackages = "org.chobit.spring.service.mapper.worker", sqlSessionFactoryRef = "workerSqlSessionFactory") public class WorkerDbConfig { @Bean(name = "workerDataSource") @ConfigurationProperties(prefix = "custom.datasource.worker") public DataSource setDataSource() { return new DruidDataSource(); } @Bean(name = "workerTransactionManager") public DataSourceTransactionManager setTransactionManager(@Qualifier("workerDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean(name = "workerSqlSessionFactory") public SqlSessionFactory setSqlSessionFactory(@Qualifier("workerDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); return bean.getObject(); } } |
在配置类的MapperScan
注解中,通过basePackages指明了该数据源所有相关的Mapper类的位置。另外,为了支持事务,这里还创建了DataSourceTransactionManager
的Bean实例。如果不需要事务支持可以取消这个Bean方法。
MyBatis有个非常有用的配置项“mapUnderscoreToCamelCase”用来自动识别下划线并转为驼峰结构,这个配置项需要在setSqlSessionFactory
方法中完成配置:
1 2 3 4 5 |
SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); org.apache.ibatis.session.Configuration conf = new org.apache.ibatis.session.Configuration(); conf.setMapUnderscoreToCamelCase(true); bean.setConfiguration(conf); |
这样完成配置后,启动程序可以看到日志中的ERROR信息消失。
使用自定义数据源,还意味着需要承担一些损失,比如:
- 大部分配置项没有默认值,需要手动配置;
- springboot原生数据源一些非常有用的特性如schema和platform将不可用;
- MyBatis的自动化配置将不可用
如果不想承担这些损失,我的建议是:换个数据库连接池试试,如Hikari或DBCP2。
多数据源支持
多数据源通常是自定义数据源配置应用最多的场景了,接下来演示下是如何完成的。
首先,肯定是要在spring配置文件中添加另一个数据库的配置信息了:
1 2 3 4 5 6 7 8 9 10 |
custom: datasource: worker: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.h2.Driver url: jdbc:h2:mem:worker master: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.h2.Driver url: jdbc:h2:mem:master |
这里添加了另一个h2内存数据库master,然后添加master数据库对应的数据源配置:
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 |
@Configuration @MapperScan(basePackages = "org.chobit.spring.service.mapper.master", sqlSessionFactoryRef = "masterSqlSessionFactory") public class MasterDbConfig { @Primary @Bean(name = "masterDataSource") @ConfigurationProperties(prefix = "custom.datasource.master") public DataSource setDataSource() { return new DruidDataSource(); } @Primary @Bean(name = "masterTransactionManager") public DataSourceTransactionManager setTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Primary @Bean(name = "masterSqlSessionFactory") public SqlSessionFactory setSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); return bean.getObject(); } } |
可以看到Master数据库的配置与Worker数据库的差别不大。唯一不同的是Master数据库配置中,每个Bean的set方法上多了一个@Primary
注解。
@Primary
注解表示同一个类出现多个可用Bean时,将绑定@Primary
注解的Bean。这里的几个Bean,transactionManager的@Primary
注解不使用事务的话可以省略,sqlSessionFactory的@Primary
注解没有的话使用某些spring版本启动会出错。不过在我的测试应用(版本:springboot 2.1.7.RELEASE)中,没有使用@Primary
也没问题。通过debug日志可以看到,使用@Primary
注解会影响数据源自动化配置和MyBatis自动化配置,前者用不着,后者用不了,所以也就没啥影响了。
transactionManager的@Primary
注解还是有用的。如果没有@Primary
注解,为方法添加事务注解需要指明使用哪个transactionManager的Bean,如下:
1 2 3 4 5 6 7 8 9 |
@Transactional(rollbackFor = Exception.class, transactionManager = "masterTransactionManager") public Master get0() { insert(); Master m = get(1); if (null == m.getJobTitle()) { throw new RuntimeException(); } return m; } |
如果为transactionManager添加了@Primary
注解,就会默认使用@Primary
注解的transactionManager。因此建议为使用事务较多的数据源的transactionManager添加@Primary
注解。
还有一点,每个数据源指向的basePackages是不一样的,需要将不同数据源的Mapper类置于不同的目录下。
写了一个测试应用spring-boot-database,上传到了GitHub,有需要可以参考下。
发表评论