一, 前言
作为一个资深的 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.YAML(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.YAML 中便于属性自动注入, 但同时, 对每一组数据源配置信息, 需要加上前缀用以区分.
- 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: [email protected]#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 也能正常使用.
********************************************************************************************************************************************************************
打完收工
********************************************************************************************************************************************************************
来源: http://www.bubuko.com/infodetail-3650723.html