tags: multi-datasource java springbootjava
一句话归纳:Spring Boot开发中链接多个数据库进行读写操做,使用多套数据源是最直接、简单的方式。
在开发过程当中,避免不了须要同时操做多个数据库的状况,一般的应用场景以下 :mysql
使用 Spring Boot 该如何处理多个数据库的读写,通常有如下几种策略:git
本系列文章“搞定SpringBoot多数据源”将针对以上几个策略进行描述,本文是第一篇:“多套数据源”,主要以主从场景为实例,结合代码,对多套数据源的实现进行描述,内容包括搭建 Spring Boot + MyBatis Plus 工程、多数据源配置、多数据源处理与使用逻辑。github
本文所涉及到的示例代码:https://github.com/mianshenglee/my-example/tree/master/multi-datasource
,读者可结合一块儿看。web
JDK1.8
2.2.2.RELEASE
3.3.0
IDEA
3.3.9
5.6.26
1.18.10
多套数据源,顾名思义每个数据库有一套独立的操做。从下往上,数据库、会话工厂、DAO操做,服务层都是独立的一套,以下所示:spring
本示例中,以一主一从两个数据库,两数据库的分别有一个表 test_user
,表结构一致,为便于说明,两个表中的数据是不同的。两个表结构可在示例代码中的 sql
目录中获取。sql
使用 spring.io构建初始 Spring Boot 工程,选用如下几个构件:数据库
MyBatis Plus 是对 MyBatis 加强,简化 DAO 操做,提升数据库操做效率。依赖以下:apache
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.0</version> </dependency>
主要添加如下几个包:后端
├─config ---------------------------------- // 数据源配置 ├─controller ------------------------------ // web服务 ├─entity ---------------------------------- // 实体类 │ ├─master │ └─slave ├─mapper ---------------------------------- // dao操做类 │ ├─master │ └─slave └─vo -------------------------------------- // 视图返回对象
注:
- 因为示例简单,省略service层
- 实体类及mapper均根据主从进行划分
Spring Boot 的默认配置文件是 application.properties
,因为有两个数据库配置,独立配置数据库是好的实践,所以添加配置文件 jbdc.properties
,添加如下自定义的主从数据库配置:
# master spring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.master.jdbc-url=jdbc:mysql://localhost:3306/mytest?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8 spring.datasource.master.username=root spring.datasource.master.password=111111 # slave spring.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.slave.jdbc-url=jdbc:mysql://localhost:3306/my_test1?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8 spring.datasource.slave.username=root spring.datasource.slave.password=111111
有了数据源链接信息,须要把数据源注入到 Spring 中。因为每一个数据库使用独立的一套数据库链接,数据库链接使用的 SqlSession
进行会话链接,SqlSession
是由SqlSessionFactory
生成。所以,须要分别配置SqlSessionFactory
。如下操做均在 config
目录 下:
(1)添加 DataSourceConfig
配置文件,注入主从数据源
@Configuration @PropertySource("classpath:config/jdbc.properties") public class DatasourceConfig { @Bean("master") @ConfigurationProperties(prefix = "spring.datasource.master") public DataSource masterDataSource(){ return DataSourceBuilder.create().build(); } @Bean("slave") @ConfigurationProperties(prefix = "spring.datasource.slave") public DataSource slaveDataSource(){ return DataSourceBuilder.create().build(); } }
- 注解
PropertySource
指定配置信息文件- 注解
ConfigurationProperties
指定主从配置前缀- 分别指定主从数据源的 bean 名称为
master
,slave
(2)添加 MasterMybatisConfig
配置文件,注入 Master 的SqlSessionFactory
@Configuration @MapperScan(basePackages = "me.mason.demo.basicmultidatasource.mapper.master", sqlSessionFactoryRef = "masterSqlSessionFactory") public class MasterMybatisConfig { /** * 注意,此处须要使用MybatisSqlSessionFactoryBean,不是SqlSessionFactoryBean, * 不然,使用mybatis-plus的内置函数时就会报invalid bound statement (not found)异常 */ @Bean("masterSqlSessionFactory") public SqlSessionFactory masterSqlSessionFactory(@Qualifier("master") DataSource dataSource) throws Exception { // 设置数据源 MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean(); mybatisSqlSessionFactoryBean.setDataSource(dataSource); //mapper的xml文件位置 PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); String locationPattern = "classpath*:/mapper/master/*.xml"; mybatisSqlSessionFactoryBean.setMapperLocations(resolver.getResources(locationPattern)); //对应数据库的entity位置 String typeAliasesPackage = "me.mason.demo.basicmultidatasource.entity.master"; mybatisSqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage); return mybatisSqlSessionFactoryBean.getObject(); } }
- 注解
MapperScan
指定那些包下的mapper
使用本数据源,并指定使用哪一个SqlSessionFactory
,注意,此处的sqlSessionFactoryRef
即本配置中的注入的SqlSessionFactory
。- 设置指定的数据源,此处是名为
master
的数据源,使用Qualifier
指定。- MyBatis Plus 对应的 Mapper 如有自定义的 mapper.xml, 则使用
setMapperLocations
指定。- 若须要对实体进行别名处理,则使用
setTypeAliasesPackage
指定。
(3)添加 SlaveMybatisConfig
配置文件,注入Slave 的 SqlSessionFactory
与(2)一致,把 master 改成 slave便可。
在 MyBatis 配置中,实体设置 typeAliases
能够简化 xml 的配置,前面提到,使用 typeAliasesPackage
设置实体路径,在 entity
包下分别设置 master
和 slave
包,存放两个库对应的表实体,使用 Lombok 简化实体操做。以下:
@Data @TableName("test_user") public class MasterTestUser implements Serializable { private static final long serialVersionUID = 1L; /** id */ private Long id; /** 姓名 */ private String name; ... }
在 mapper
包下,分别添加 master
和 slave
包,存放两个库对应的 Mapper ,因为 MyBatis Plus 自己已包含基本的 CRUD 操做,因此不少时候能够不用 xml 文件配置。若须要自定义操做,须要结合 xml文件,与此同时须要指定对应的 xml 文件所在目录。以下:
@Repository public interface MasterTestUserMapper extends BaseMapper<MasterTestUser> { /** * 自定义查询 * @param wrapper 条件构造器 */ List<MasterTestUser> selectAll(@Param(Constants.WRAPPER)Wrapper<MasterTestUser> wrapper); }
slave对应的Mapper与此相似
MyBatis Plus 的默认mapper xml 文件路径为 classpath*:/mapper/**/*.xml
,即 resources/mapper
下,一样设置 master
及 slave
目录,分别存放对应的mapper xml 文件。如下是 master 的自定义操做:
<mapper namespace="me.mason.demo.basicmultidatasource.mapper.master.MasterTestUserMapper"> <select id="selectAll" resultType="masterTestUser"> select * from test_user <if test="ew!=null"> ${ew.customSqlSegment} </if> </select> </mapper>
通过上面的多套数据源配置,可知道,若须要操做哪一个数据库,直接使用对应的 mapper 进行 CRUD 操做便可。以下为 Controller 中分别查询两个库,获取到的数据合在一块儿返回:
@RestController @RequestMapping("/user") public class TestUserController { @Autowired private MasterTestUserMapper masterTestUserMapper; @Autowired private SlaveTestUserMapper slaveTestUserMapper; /** * 查询所有 */ @GetMapping("/listall") public Object listAll() { //master库,自定义接口查询 QueryWrapper<MasterTestUser> queryWrapper = new QueryWrapper<>(); List<MasterTestUser> resultData = masterTestUserMapper.selectAll(queryWrapper.isNotNull("name")); //slave库,mp内置接口 List<SlaveTestUser> resultDataSlave = slaveTestUserMapper.selectList(null); //返回 Map<String, Object> result = new HashMap<>(); result.put("master" , resultData); result.put("slave" , resultDataSlave); return ResponseResult.success(result); } }
- 使用Autowired注解注入对应的mapper
- 使用对应数据库的 mapper 进行业务操做
- 根据业务在数据库中执行相应的操做,如主只作增删改操做、从只读操做
至此,多数据源的实现已完成,当前示例是两个同构的数据库,固然,如果异构的数据库,或者多于两个的数据库,处理方式是同样的,只不过是把数据源增长一套而已。
由上述说明,咱们能够总结一下使用多套数据源的方法进行多数据库操做,它的优缺点是什么。
SqlSessionFactory
是一个工厂,建议是使用单例,彻底能够重用,不须要创建多个,只须要更改数据源便可,跟多线程,使用线程池减小资源消耗是同一道理。正由于有上述的缺点,因此还有改进的空间。因而就有了动态数据源,至于动态数据源如何实现,下回分解。
本文对多个数据库的操做进行了初步探讨,并对使用多套源的策略进行讲解,结合主从代码示例,搭建了 Spring Boot + MyBatis Plus 工程,配置多数据源及使用 Mapper 进行多数据源操做,最后对多套数据源的优缺点进行总结。但愿小伙伴们能够对多数据源操做有个初步印象。
本文有配套的示例代码,有兴趣的能够跑一下示例来感觉一下。
https://www.liaoxuefeng.com/article/1182502273240832
https://juejin.im/post/5b790a866fb9a019ea01f38c
https://juejin.im/post/5cb0023d5188250df17d4ffc
https://juejin.im/post/5a927d23f265da4e7e10d740
个人公众号(搜索Mason技术记录
),获取更多技术记录: