SpringBoot整合MyBatis多数据源
一、介绍
在平常的项目中,我们有连接数据库的需求。一般都是一个项目一个数据库,但也有例外需要连接多个数据库的。
那么该如何配置,可以达到多数据源的需求呢。
本次为SpringBoot
与MyBatis
的整合,其实掌握了需要配置什么,也很容易进行复刻。
二、配置
1)数据库准备
首先,我们先准备三个数据库吧,这边都使用MySQL
了,实际可以是不同的数据库
-
test
数据库
1 2 3 4 5 6 7 8 9 10 11
| create database `test` character set utf8mb4 collate utf8mb4_general_ci;
CREATE TABLE `sys_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT '用户名', `password` varchar(128) NOT NULL COMMENT '密码', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (1, 'banmoon', '1234'); INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (2, 'user', '1234');
|
-
test01
数据库
1 2 3 4 5 6 7 8 9 10 11
| create database `test01` character set utf8mb4 collate utf8mb4_general_ci;
CREATE TABLE `sys_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT '用户名', `password` varchar(128) NOT NULL COMMENT '密码', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (1, 'test01', '1234'); INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (2, 'test01User', '1234');
|
-
test02
数据库
1 2 3 4 5 6 7 8 9 10 11
| create database `test02` character set utf8mb4 collate utf8mb4_general_ci;
CREATE TABLE `sys_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT '用户名', `password` varchar(128) NOT NULL COMMENT '密码', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (1, 'test02', '1234'); INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (2, 'test02User', '1234');
|
2)配置
首先,maven
依赖包不能忘记
1 2 3 4 5 6 7 8 9 10
| <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency>
|
然后,我们需要在配置文件上配置上三个数据库的配置信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&allowMultiQueries=true username: root password: 1234
dynamic-datasource: test01: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test01?serverTimezone=Asia/Shanghai&allowMultiQueries=true username: root password: 1234 test02: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test02?serverTimezone=Asia/Shanghai&allowMultiQueries=true username: root password: 1234
|
怎么配置不重要,清爽就好,重点在于读取。
我们需要读取上面配置文件的信息,配置生成SqlSessionTemplate
、SqlSessionFactory
、PlatformTransactionManager
,如此来达到多数据源的功能
test
数据库连接的相关配置
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| package com.banmoon.test.config.datasource;
import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; 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 org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
@Configuration @MapperScan(basePackages = {"com.banmoon.test.persistent.master.mapper"}, sqlSessionFactoryRef = "masterSqlSessionFactory") public class MasterDatasourceConfig {
@Primary @Bean("masterDatasourceProperties") @ConfigurationProperties(prefix = "spring.datasource") public DataSourceProperties dataSourceProperties(){ return new DataSourceProperties(); }
@Primary @Bean("masterDatasource") public DataSource dataSource(@Qualifier("masterDatasourceProperties") DataSourceProperties properties){ DataSource build = DataSourceBuilder.create() .driverClassName(properties.getDriverClassName()) .url(properties.getUrl()) .username(properties.getUsername()) .password(properties.getPassword()) .build(); return build; }
@Primary @Bean(name = "masterTransactionManager") public PlatformTransactionManager dataSourceTransactionManager(@Qualifier("masterDatasource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
@Bean(name = "masterSqlSessionFactory") public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDatasource") DataSource dataSource) throws Exception { final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource); sessionFactoryBean.setTypeHandlersPackage("com.banmoon.test.persistent.master.entity"); sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/master/*.xml")); return sessionFactoryBean.getObject(); }
@Primary @Bean(name = "masterSqlSessionTemplate") public SqlSessionTemplate sqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); }
}
|
test01
数据库连接的相关配置
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| package com.banmoon.test.config.datasource;
import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; 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 org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
@Configuration @MapperScan(basePackages = {"com.banmoon.test.persistent.test01.mapper"}, sqlSessionFactoryRef = "test01SqlSessionFactory") public class Test01DatasourceConfig {
@Bean("test01DatasourceProperties") @ConfigurationProperties(prefix = "dynamic-datasource.test01") public DataSourceProperties dataSourceProperties(){ return new DataSourceProperties(); }
@Primary @Bean("test01Datasource") public DataSource dataSource(@Qualifier("test01DatasourceProperties") DataSourceProperties properties){ DataSource build = DataSourceBuilder.create() .driverClassName(properties.getDriverClassName()) .url(properties.getUrl()) .username(properties.getUsername()) .password(properties.getPassword()) .build(); return build; }
@Primary @Bean(name = "test01TransactionManager") public PlatformTransactionManager dataSourceTransactionManager(@Qualifier("test01Datasource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
@Bean(name = "test01SqlSessionFactory") public SqlSessionFactory sqlSessionFactory(@Qualifier("test01Datasource") DataSource dataSource) throws Exception { final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource); sessionFactoryBean.setTypeHandlersPackage("com.banmoon.test.persistent.test01.entity"); sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/test01/*.xml")); return sessionFactoryBean.getObject(); }
@Primary @Bean(name = "test01SqlSessionTemplate") public SqlSessionTemplate sqlSessionTemplate(@Qualifier("test01SqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); }
}
|
test02
数据库连接的相关配置
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| package com.banmoon.test.config.datasource;
import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; 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 org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
@Configuration @MapperScan(basePackages = {"com.banmoon.test.persistent.test02.mapper"}, sqlSessionFactoryRef = "test02SqlSessionFactory") public class Test02DatasourceConfig {
@Bean("test02DatasourceProperties") @ConfigurationProperties(prefix = "dynamic-datasource.test02") public DataSourceProperties dataSourceProperties(){ return new DataSourceProperties(); }
@Primary @Bean("test02Datasource") public DataSource dataSource(@Qualifier("test02DatasourceProperties") DataSourceProperties properties){ DataSource build = DataSourceBuilder.create() .driverClassName(properties.getDriverClassName()) .url(properties.getUrl()) .username(properties.getUsername()) .password(properties.getPassword()) .build(); return build; }
@Primary @Bean(name = "test02TransactionManager") public PlatformTransactionManager dataSourceTransactionManager(@Qualifier("test02Datasource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
@Bean(name = "test02SqlSessionFactory") public SqlSessionFactory sqlSessionFactory(@Qualifier("test02Datasource") DataSource dataSource) throws Exception { final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource); sessionFactoryBean.setTypeHandlersPackage("com.banmoon.test.persistent.test02.entity"); sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/test02/*.xml")); return sessionFactoryBean.getObject(); }
@Primary @Bean(name = "test02SqlSessionTemplate") public SqlSessionTemplate sqlSessionTemplate(@Qualifier("test02SqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); }
}
|
还有一个需要注意,我们需要排除掉MybatisAutoConfiguration
类,避免它自动进行配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.banmoon.test;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(exclude = MybatisAutoConfiguration.class) public class TestApplication {
public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); }
}
|
配置完成,那么该如何去写Entity
和Mapper
呢?
请注意,在我们构建sqlSessionFactory
的时候,就已经指定了它Entity
的包路径和Mapper
的包路径。
所以我只需要在指定的包路径在创建Entity
和Mapper
就可以了。
3)编写实体和Mapper
如下进行编写User.java
、UserMapper.java
、UserMapper.xml
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
| package com.banmoon.test.persistent.master.entity;
import java.io.Serializable; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors;
@Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String username;
private String password;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.banmoon.test.persistent.master.mapper;
import com.banmoon.test.persistent.master.entity.User; import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper public interface UserMapper {
List<User> selectList();
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.banmoon.test.persistent.master.mapper.UserMapper">
<resultMap id="BaseResultMap" type="com.banmoon.test.persistent.master.entity.User"> <id column="id" property="id" /> <result column="username" property="username" /> <result column="password" property="password" /> </resultMap> <select id="selectList" resultType="com.banmoon.test.persistent.master.entity.User"> select * from sys_user </select>
</mapper>
|
由于演示的三个数据库,里面建的表结构都是一样的,这里就不再贴代码了,贴一个包路径结构
4)测试
以前我还很喜欢写Controller
去进行测试,现在直接单元测试,直接进行调试了,简单快捷
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
| package com.banmoon.test;
import com.banmoon.test.persistent.master.entity.User; import com.banmoon.test.persistent.master.mapper.UserMapper; import com.banmoon.test.persistent.test01.entity.Test01User; import com.banmoon.test.persistent.test01.mapper.Test01UserMapper; import com.banmoon.test.persistent.test02.entity.Test02User; import com.banmoon.test.persistent.test02.mapper.Test02UserMapper; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest class ServiceTest {
@Autowired private UserMapper userMapper;
@Autowired private Test01UserMapper test01UserMapper;
@Autowired private Test02UserMapper test02UserMapper;
@Test void insertTest() { List<User> list = userMapper.selectList(); list.forEach(System.out::println);
System.out.println("============"); List<Test01User> test01UserList = test01UserMapper.selectList(); test01UserList.forEach(System.out::println);
System.out.println("============"); List<Test02User> test02UserList = test02UserMapper.selectList(); test02UserList.forEach(System.out::println); }
}
|
三、MyBatis-Plus多数据源
1)自己配置
首先就是先写入maven
依赖,这一点去官网可以查看到
1 2 3 4 5
| <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency>
|
至于多数据源的配置,其实和上面差不多的,主要需要将SqlSessionFactory
改成MyBatis-plus
中的实现就可以了,如下
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| package com.banmoon.test.config.datasource;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; 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 org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
@Configuration @MapperScan(basePackages = {"com.banmoon.test.persistent.master.mapper"}, sqlSessionFactoryRef = "masterSqlSessionFactory") public class MasterDatasourceConfig {
@Primary @Bean("masterDatasourceProperties") @ConfigurationProperties(prefix = "spring.datasource") public DataSourceProperties dataSourceProperties(){ return new DataSourceProperties(); }
@Primary @Bean("masterDatasource") public DataSource dataSource(@Qualifier("masterDatasourceProperties") DataSourceProperties properties){ DataSource build = DataSourceBuilder.create() .driverClassName(properties.getDriverClassName()) .url(properties.getUrl()) .username(properties.getUsername()) .password(properties.getPassword()) .build(); return build; }
@Primary @Bean(name = "masterTransactionManager") public PlatformTransactionManager dataSourceTransactionManager(@Qualifier("masterDatasource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
@Bean(name = "masterSqlSessionFactory") public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDatasource") DataSource dataSource) throws Exception { final MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource); sessionFactoryBean.setTypeHandlersPackage("com.banmoon.test.persistent.master.entity"); sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/master/*.xml")); return sessionFactoryBean.getObject(); }
@Primary @Bean(name = "masterSqlSessionTemplate") public SqlSessionTemplate sqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); }
}
|
注意一下,由于只需要引入MyBatis-plus
,所以启动类上的排除的类,已经可以不需要了
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.banmoon.test;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class TestApplication {
public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); }
}
|
其他都差不多,是由代码生成器生成的Entity
和Mapper
,这里就不贴了,直接翻官网文档吧,里面很详细
上代码测试一下吧,其实和之前差不多,只是使用到的是MyBatis-plus
中的方法
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
| package com.banmoon.test;
import com.banmoon.test.persistent.master.entity.User; import com.banmoon.test.persistent.master.mapper.UserMapper; import com.banmoon.test.persistent.test01.entity.Test01User; import com.banmoon.test.persistent.test01.mapper.Test01UserMapper; import com.banmoon.test.persistent.test02.entity.Test02User; import com.banmoon.test.persistent.test02.mapper.Test02UserMapper; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest class ServiceTest {
@Autowired private UserMapper userMapper;
@Autowired private Test01UserMapper test01UserMapper;
@Autowired private Test02UserMapper test02UserMapper;
@Test void insertTest() { List<User> list = userMapper.selectList(null); list.forEach(System.out::println);
System.out.println("============"); List<Test01User> test01UserList = test01UserMapper.selectList(null); test01UserList.forEach(System.out::println);
System.out.println("============"); List<Test02User> test02UserList = test02UserMapper.selectList(null); test02UserList.forEach(System.out::println); }
}
|
2)官方插件
在MyBatis-Plus中,有一个多数据源启动器,它可以做到以下这些功能
-
支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
-
支持数据库敏感配置信息 加密 ENC()。
-
支持每个数据库独立初始化表结构schema和数据库database。
-
支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
-
支持 自定义注解 ,需继承DS(3.2.0+)。
-
提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。
-
提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。
-
提供 自定义数据源来源 方案(如全从数据库加载)。
-
提供项目启动后 动态增加移除数据源 方案。
-
提供Mybatis环境下的 纯读写分离 方案。
-
提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。
-
支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
-
提供 **基于seata的分布式事务方案。
-
提供 本地多数据源事务方案。
具体还是看官网文档吧,已经写的十分详细了,建议使用!!!
四、最后
虽然最近暂时没有此类的需求,但提前先记录测试一波,免得到时候手忙脚乱。
哦对,现在的确很少使用原生的MyBatis
了,最近都是在使用MyBatis-plus
。
这是一个好框架,十分好用,建议学习,直接使用。
我是半月,祝你幸福!!!