Springboot 多数据源配置,结合tk-mybatis
一、前言
作为一个资深的CRUD工程师,我们在实际使用springboot开发项目的时候,难免会遇到同时使用多个数据库的情况,比如前脚刚查询mysql,后脚就要查询sqlserver。
这时,我们很直观的就会想到,为springboot配置多个数据源,需要用哪个数据库连接,直接@Autowired不就行了。那么问题来了,怎么配置呢?
********************************************************************************************************************************************************************
退后,我要开始装逼了
********************************************************************************************************************************************************************
二、前期工作
1.数据库。
这里我准备了一个mysql数据库和一个sqlserver数据库。
Mysql脚本:
DROP TABLE IF EXISTS `tb_user`; CREATE TABLE `tb_user` ( `id` int(8) NOT NULL, `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of tb_user -- ---------------------------- INSERT INTO `tb_user` VALUES (0, '张三'); INSERT INTO `tb_user` VALUES (1, '李四'); INSERT INTO `tb_user` VALUES (2, '王五'); INSERT INTO `tb_user` VALUES (3, '赵六'); SET FOREIGN_KEY_CHECKS = 1;
sqlserver脚本:
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[test]') AND type IN ('U')) DROP TABLE [dbo].[test] GO CREATE TABLE [dbo].[test] ( [id] int NOT NULL, [career] varchar(255) COLLATE Chinese_PRC_90_CI_AS NULL ) GO ALTER TABLE [dbo].[test] SET (LOCK_ESCALATION = TABLE) GO -- ---------------------------- -- Records of test -- ---------------------------- INSERT INTO [dbo].[test] ([id], [career]) VALUES (N'1', N'软件工程师') GO INSERT INTO [dbo].[test] ([id], [career]) VALUES (N'2', N'硬件工程师') GO INSERT INTO [dbo].[test] ([id], [career]) VALUES (N'3', N'理财顾问') GO INSERT INTO [dbo].[test] ([id], [career]) VALUES (N'4', N'律师') GO INSERT INTO [dbo].[test] ([id], [career]) VALUES (N'5', N'数学家') GO -- ---------------------------- -- Primary Key structure for table test -- ---------------------------- ALTER TABLE [dbo].[test] ADD CONSTRAINT [PK__test__3213E83F1910436D] PRIMARY KEY CLUSTERED ([id]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO
2.项目依赖。
springboot版本:2.0.6.RELEASE
依赖这里就不贴出来了,都是常见的几个starter而已。
tk.mybatis插件
这里我着重说一下tk.mybatis插件的配置。因为我们要使用该插件自动生成mapper等相关文件,但是我们又使用了两个不同的数据库,因此,需要对该插件分别作不同的参数配置,然后分别自动生成。
注意不要同时配置插件,不然会插件引入冲突。
关于如何使用tk.mybatis插件,请移步 使用mybatis-generator插件结合tk.mybatis自动生成mapper二三事
<!-- mysql 数据库 --> <!--<plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.5</version> <configuration> <configurationFile>src/main/resources/generator/generatorConfig-mysql.xml</configurationFile> <overwrite>true</overwrite> <verbose>true</verbose> </configuration> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>3.4.4</version> </dependency> </dependencies> </plugin>--> <!-- sqlserver 数据库 --> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.5</version> <configuration> <configurationFile>src/main/resources/generator/generatorConfig-sqlserver.xml</configurationFile> <overwrite>true</overwrite> <verbose>true</verbose> </configuration> <dependencies> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>sqljdbc4</artifactId> <version>${sqlserver.sqljdbc4.version}</version> </dependency> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>3.4.4</version> </dependency> </dependencies> </plugin>
三、重头戏
1.spring配置文件
我们知道在application.yml(properties)文件中,可以配置一个数据源,spring在启动时,会自动加载该配置,并实例化数据库连接:
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://192.168.139.129:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
hikari:
minimum-idle: 1
maximum-pool-size: 20
但是我们现在有多个数据源怎么办呢?难道直接粗暴的写两个?spring能自动识别两个数据源配置么?
这时,我们就需要手动使用@Bean的方式在代码中进行不同数据源的实例化配置了。为了更方便的管理配置信息,所以,我们仍然将配置信息写在application.yml中便于属性自动注入,但同时,对每一组数据源配置信息,需要加上前缀用以区分。
spring: datasource: test-mysql: type: com.zaxxer.hikari.HikariDataSource url: jdbc:mysql://192.168.139.129:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root driver-class-name: com.mysql.jdbc.Driver hikari: minimum-idle: 1 maximum-pool-size: 20 test-sqlserver: type: com.zaxxer.hikari.HikariDataSource url: jdbc:sqlserver://192.168.139.129;DatabaseName=dbo username: sa password: qwe!@#123 driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver hikari: minimum-idle: 1 maximum-pool-size: 20
2.手动配置数据源
通过手动配置数据源,分别实例化不同的数据源连接对象,以实现spring的多数据源配置。由于多个数据源对于spring来说都是DataSource及其相关类型的Bean,那么在spring容器进行DataSource实例化注入容器的时候,就会很困惑:WDNMD,你给劳资搞了几个数据源啊?这么多“妹子”,我先“嘿咻”谁?所以,为了让spring能够顺利的实例化我们配置的所有DataSource,就需要我们手动指定优先级,使用@Primary注解告知spring当前Bean的优先级更高。
主数据源(mysql)
package com.zhangyu.springboot.multidatasource.config; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.beans.factory.annotation.Qualifier; 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.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import tk.mybatis.spring.annotation.MapperScan; import javax.sql.DataSource; // mysql数据源配置(主数据源) @Configuration @MapperScan(basePackages = "com.zhangyu.springboot.multidatasource.mapper.mysql", sqlSessionTemplateRef = "mysqlSqlSessionTemplate") public class TestMysqlDataSourceConfig { // 注入数据源配置 @Primary @Bean @ConfigurationProperties(prefix = "spring.datasource.test-mysql") public DataSourceProperties mysqlDataSourceProperties() { return new DataSourceProperties(); } // 创建数据库连接 @Primary @Bean public DataSource mysqlDataSource() { return mysqlDataSourceProperties().initializeDataSourceBuilder().build(); } // 创建session工厂 @Primary @Bean public SqlSessionFactory mysqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource); sessionFactoryBean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml")); return sessionFactoryBean.getObject(); } // 创建事务管理(按需添加) @Primary @Bean public DataSourceTransactionManager mysqlDataSourceTransactionManager() { return new DataSourceTransactionManager(mysqlDataSource()); } // 会话管理 @Primary @Bean public SqlSessionTemplate mysqlSqlSessionTemplate(@Qualifier("mysqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }
次数据源(sqlserver)
package com.zhangyu.springboot.multidatasource.config; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import tk.mybatis.spring.annotation.MapperScan; import javax.sql.DataSource; // sqlserver数据源配置 @Configuration @MapperScan(basePackages = "com.zhangyu.springboot.multidatasource.mapper.sqlserver", sqlSessionTemplateRef = "sqlServerSqlSessionTemplate") public class TestSqlServerDataSourceConfig { // 注入数据源配置 @Bean @ConfigurationProperties(prefix = "spring.datasource.test-sqlserver") public DataSourceProperties sqlServerDataSourceProperties() { return new DataSourceProperties(); } // 创建数据库连接 @Bean public DataSource sqlServerDataSource() { return sqlServerDataSourceProperties().initializeDataSourceBuilder().build(); } // 创建session工厂 @Bean public SqlSessionFactory sqlServerSessionFactory(@Qualifier("sqlServerDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource); sessionFactoryBean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml")); return sessionFactoryBean.getObject(); } // 创建事务管理(按需添加) @Bean public DataSourceTransactionManager sqlServerDataSourceTransactionManager() { return new DataSourceTransactionManager(sqlServerDataSource()); } // 会话管理 @Bean public SqlSessionTemplate sqlServerSqlSessionTemplate(@Qualifier("sqlServerSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }
再啰嗦几句,mybatis是通过配置的扫描包和对应的sqlSessionTemplate来自动切换数据源,即通过在 @MapperScan 注解中配置 basePackages 和 sqlSessionTemplateRef。
四、尾声
启动项目,可以看到控制台打印如下信息:
INFO 12840 --- [)-26.12.195.117] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... INFO 12840 --- [)-26.12.195.117] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. INFO 12840 --- [)-26.12.195.117] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Starting... INFO 12840 --- [)-26.12.195.117] com.zaxxer.hikari.pool.PoolBase : HikariPool-2 - Driver does not support get/set network timeout for connections. (null) INFO 12840 --- [)-26.12.195.117] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Start completed.
很明显实例化了两个 HikariPool ,实际使用又如何呢?
Usermapper连接的mysql数据库,TestMapper连接的sqlserver数据库:
//Service:
public List<TbUser> getUserList() { return userMapper.selectAll(); } public List<Test> getTestList() { return testMapper.selectAll(); }
分别调用,能都正常获取数据。
至此,springboot双数据源配置完成,tk-mybatis也能正常使用。
********************************************************************************************************************************************************************
打完收工
********************************************************************************************************************************************************************