之前介绍了Spring Boot 整合mybatis 使用注解方式配置的方式实现增删改查以及一些复杂自定义的sql 语句 。想必大家对spring boot 项目中,如何使用mybatis 有了一定的了解。但在很多业务场景下,我们需要在一个项目中配置多个数据源来实现业务逻辑,例如:现有电商业务,商品和库存数据分别放在不同的数据库中,这就要求我们的系统架构支持同时配置多个数据源实现相关业务操作。那么Spring Boot 如何应对这种多数据源的场景呢?其实,在 Spring Boot 项目中配置多数据源十分便捷。接下来就聊一聊 Spring Boot 整合mybatis 实现多数据源的相关配置。
关于整合mybatis 部分,之前已经介绍过,这里直接讲 Mybatis 多数据源的配置的配置实现,不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhong/category/1657780.html。
一、配置数据库
首先在系统配置文件中,需要配置多个数据源,即在application.properties 文件中增加如下配置:
# mybatis 多数据源配置 # 数据库1的配置 spring.datasource.test1.driver-class-name = com.mysql.jdbc.Driver spring.datasource.test1.jdbc-url = jdbc:mysql://localhost:3306/zwz_test?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.test1.username = root spring.datasource.test1.password = root # 数据库2的配置 spring.datasource.test2.driver-class-name = com.mysql.jdbc.Driver spring.datasource.test2.jdbc-url = jdbc:mysql://localhost:3306/zwz_test2?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.test2.username = root spring.datasource.test2.password = root
注意:
1、这里配置的是两个一样的数据库zwz_test 和zwz_test2。
2、数据库连接的配置使用jdbc-url , 不是之前的url ,这点需要注意。
二、数据源配置类
1、主数据源配置类
在config 包中,创建 DataSource1Config 类。此类配置主数据源。
package com.weiz.config; 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.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.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; @Configuration @MapperScan(basePackages = "com.weiz.mapper.test1", sqlSessionFactoryRef = "test1SqlSessionFactory") public class DataSource1Config { @Bean(name = "test1DataSource") @ConfigurationProperties(prefix = "spring.datasource.test1") @Primary public DataSource testDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "test1SqlSessionFactory") @Primary public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); return bean.getObject(); } @Bean(name = "test1TransactionManager") @Primary public DataSourceTransactionManager testTransactionManager(@Qualifier("test1DataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean(name = "test1SqlSessionTemplate") @Primary public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }
2、配置其他数据源
在config 包中,创建DataSource2Config 类。此类配置其他普通数据源。
package com.weiz.config; 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.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.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; @Configuration @MapperScan(basePackages = "com.weiz.mapper.test2", sqlSessionFactoryRef = "test2SqlSessionFactory") public class DataSource2Config { @Bean(name = "test2DataSource") @ConfigurationProperties(prefix = "spring.datasource.test2") public DataSource testDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "test2SqlSessionFactory") public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); return bean.getObject(); } @Bean(name = "test2TransactionManager") public DataSourceTransactionManager testTransactionManager(@Qualifier("test2DataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean(name = "test2SqlSessionTemplate") public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }
说明, DataSource1Config 和 DataSource2Config 即是相关的主数据源配置类和普通数据源配置类。
com.weiz.mapper.test1 为 扫描的mapper的路径。
可以看到两个数据源都配置的各自的DataSource、SqlSessionFactory、TransactionManager和SqlSessionTemplate 。
虽然两个类看着差不多,但是需要特别注意以下几点:
1、主数据源配置需要加@Primary 注解,其他普通数据源不能加这个注解,否则会报错,复制的时候小心。
2、各个数据源配置的 basePackages 扫描路径需要配置正确。配置错了不会出异常,但是运行的时候,会找错数据库。
3、如何调用
首先,创建com.weiz.mapper.test1 和 com.weiz.mapper.test2 包,将之前的UserMapper ,重名命为User1Mapper 和User2Mapper 复制到相应的包中。
然后,UserServiceImpl 分别注入两个不同的 Mapper,想操作哪个数据源就使用哪个数据源的 Mapper 进行操作处理。
package com.weiz.service.impl; import com.weiz.mapper.test1.User1Mapper; import com.weiz.mapper.test2.User2Mapper; import com.weiz.pojo.User; import com.weiz.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Autowired private User1Mapper user1Mapper; @Autowired private User2Mapper user2Mapper; @Override public int saveUser(User user) { user1Mapper.insert(user); return user2Mapper.insert(user); } @Override public int updateUser(User user) { user1Mapper.updateByPrimaryKey(user); return user2Mapper.updateByPrimaryKey(user); } @Override public int deleteUser(String userId) { user1Mapper.deleteByPrimaryKey(userId); return user2Mapper.deleteByPrimaryKey(userId); } @Override public User queryUserById(String userId) { user1Mapper.selectByPrimaryKey(userId); return user2Mapper.selectByPrimaryKey(userId); } }
这里是一个简单的测试程序,实际项目中是根据实际的业务,调用不同的mapper 实现的,或者通过注解配置,动态切换数据源。
三、验证测试
启动项目,浏览器中输入如下地址: http://localhost:8088/mybatis/saveuser ,可以看到两个数据库中,都增加了一条用户信息。
数据库 zwz_test 中 用户表sys_user 增加了一条记录。
数据库 zwz_test2 中 用户表sys_user 也增加了一条同样的记录。
四、可能会遇到的坑
1、数据库连接的配置使用jdbc-url , 不是之前的url 。这点需要注意。
2、主数据源配置需要加@Primary 注解,其他普通数据源不能加这个注解,否则会报错,复制的时候小心。
3、各个数据源配置的 basePackages 扫描路径需要配置正确。配置错了不会出异常,但是运行的时候,会找错数据库。
4、如果Mybatis使用的是xml 配置版,xml位置需要在每个config显示置顶位置。
最后
以上,就把Spring Boot整合Mybatis,实现多数据源配置的功能介绍完了。操作看似简单,其实还是得小心仔细。不然很容易出错。
此外配置多数据源之后,还涉及到数据源切换的问题,网上有很多种方法,比较流行的就是druid框架实现多数据源切换。这个后面再讲吧。
还有,这里没有使用事务,如果采用事务需要分别配置每个数据源的事务,并采用事务性注解进行统一管理。这里不细说大家自己研究吧。
这个系列课程的完整源码,也会提供给大家。大家关注我的微信公众号(架构师精进),回复:springboot源码。获取这个系列课程的完整源码。
推荐阅读:
SpringBoot从入门到精通(二十二)使用Swagger2优雅构建 RESTful API文档
SpringBoot从入门到精通(二十一)如何优雅的设计 RESTful API 接口版本号,实现 API 版本控制!
SpringBoot从入门到精通(二十)快速构建RESTful Web API 服务
SpringBoot从入门到精通(十九)使用注解实现动态Sql、参数传递
SpringBoot从入门到精通(十八)Mybatis系列之——使用注解的方式实现后台管理功能
SpringBoot从入门到精通(十七)MyBatis系列之——创建自定义mapper 实现多表关联查询!
SpringBoot从小白到精通(十六)使用pagehelper实现分页查询功能
SpringBoot从小白到精通(十四)使用JdbcTemplate操作数据库,配置多数据源!
SpringBoot从小白到精通(十二)logback日志配置
SpringBoot从小白到精通(十)使用Interceptor拦截器,一学就会!
SpringBoot从小白到精通(九)使用@Async实现异步执行任务
SpringBoot从小白到精通(八)熟悉@EnableScheduling,一秒搞定定时任务
SpringBoot从小白到精通(七)使用Redis实现高速缓存架构
SpringBoot从小白到精通(六)使用Mybatis实现增删改查【附详细步骤】
SpringBoot从小白到精通(五)Thymeleaf的语法及常用标签
SpringBoot从小白到精通(四)Thymeleaf页面模板引擎