学习链接
spring整合mybatis的核心思路 & 数据源动态切换 & 多数据源事务控制 - 自己的链接(本篇文章的上篇)
Mybatisplus生成代码配置 & p6spy打印sql & mybatis日志打印 & mybatisplus用法
dynamic-datasource-spring-boot-starter 的gitee地址
dynamic-datasource官方文档(收费)(使用自己的qq登录即可)
SpringBoot多数据源
【Java多数据源实现教程】实现动态数据源、多数据源切换方式
springboot多数据源使用
SpringBoot实现多数据源(六)【dynamic-datasource 多数据源组件】
【Java多数据源实现教程】实现动态数据源、多数据源切换方式
Springboot多数据源配置详解
SpringBoot多数据源配置
基础介绍
简介
dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。
其支持 Jdk 1.7+, SpringBoot 1.4.x 1.5.x 2.x.x。
特性
- 支持
数据源分组
,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。 - 支持数据库敏感配置信息 加密 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的分布式事务方案
。 - 提供
本地多数据源事务方案(不能和原生spring事务混用)
约定
- 本框架
只做 切换数据源
这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何CRUD。 - 配置文件所有
以下划线 _ 分割的数据源 首部 即为组的名称
,相同组名称的数据源会放在一个组下
。 - 切换数据源
可以是组名
,也可以是具体数据源名称
。组名则切换时采用负载均衡算法切换
。 默认的数据源名称为 master
,你可以通过 spring.datasource.dynamic.primary
修改。方法上的注解优先于类上注解
。- DS支持继承抽象类上的DS,暂
不支持继承接口上的DS
。
使用方法
1. 引入dynamic-datasource-spring-boot-starter
<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>${version}</version>
</dependency>
2. 配置数据源
以下会配置一个默认库master,一个组slave(组名
)下有两个子库slave_1(组名为slave组下的数据源名称slave_1
) 和 slave_2(组名为slave组下的数据源名称slave_2
)
spring:datasource:dynamic:primary: master #设置默认的数据源或者数据源组,默认值即为masterstrict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源datasource:master:url: jdbc:mysql://xx.xx.xx.xx:3306/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置slave_1:url: jdbc:mysql://xx.xx.xx.xx:3307/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverslave_2:url: ENC(xxxxx) # 内置加密,使用请查看详细文档username: ENC(xxxxx)password: ENC(xxxxx)driver-class-name: com.mysql.jdbc.Driver#......省略
其它配置示例
# 多主多从 纯粹多库(记得设置primary) 混合配置
spring: spring: spring:datasource: datasource: datasource:dynamic: dynamic: dynamic:datasource: datasource: datasource:master_1: mysql: master:master_2: oracle: slave_1:slave_1: sqlserver: slave_2:slave_2: postgresql: oracle_1:slave_3: h2: oracle_2:
3. 使用 @DS 切换数据源
@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解
。
@Service
@DS("slave")
public class UserServiceImpl implements UserService {@Autowiredprivate JdbcTemplate jdbcTemplate;public List selectAll() {return jdbcTemplate.queryForList("select * from user");}@Override@DS("slave_1")public List selectByCondition() {return jdbcTemplate.queryForList("select * from user where age >10");}
}
数据源切换示例
简单演示下使用@DS注解,切换指定的数据源
准备数据库
准备2个数据库,一个m_db(作为主库),一个s_db(作为从库),这2个数据库中都有一张account表,表中仅有id和nick_name字段
CREATE TABLE `account` (`id` int(11) NOT NULL AUTO_INCREMENT,`nick_name` varchar(50) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
pom.xml
导入mybatis-plus(不一定要用mybatis-plus,只是因为懒得自己写mapper.xml文件) 和 dynamic-datasource 的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><!--父工程--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.8.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><!--项目GAV坐标--><groupId>com.zzhua</groupId><artifactId>sdynamic-datasource-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>springboot-demo</name><description>Demo project for Spring Boot</description><!--版本--><properties><java.version>1.8</java.version></properties><dependencies><!--web启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.3</version></dependency><dependency><groupId>p6spy</groupId><artifactId>p6spy</artifactId><version>3.9.1</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.1</version></dependency><!--swagger2依赖--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version> 2.7.0</version></dependency><!--swagger-ui第三方依赖--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>swagger-bootstrap-ui</artifactId><version>1.9.6</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--打开提示--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><!--测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
application.yml
#spring:
# datasource:
# type: com.zaxxer.hikari.HikariDataSource
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/m_db?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
# username: root
# password: rootspring:datasource:dynamic:primary: masterstrict: truedatasource:master:url: jdbc:mysql://127.0.0.1:3306/m_db?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driverhikari:min-idle: 2max-pool-size: 5# 使用下划线, 下划线前面的是组名,整个为数据源标识(若@DS中使用组名, 则会负载均衡该组名下的所有数据源)slave_1:url: jdbc:mysql://127.0.0.1:3306/s_db?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Drivermybatis-plus:mapper-locations: classpath:mapper/**.xml
SpringbootDemoApplication
开启mybatis的mapper接口扫描
@SpringBootApplication
@MapperScan("com.zzhua.mapper")
public class SpringbootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringbootDemoApplication.class, args);}}
AccountController
@RestController
@RequestMapping("/account")
public class AccountController {@Autowiredprivate IAccountService accountService;@RequestMapping("createAccount")public Object createAccount(@RequestParam("nickName") String nickName) {Account account = new Account();account.setNickName(nickName);accountService.addAccount(account);return "ok";}@RequestMapping("getAccounts")public List<Account> getAccounts() {return accountService.findAll();}}
IAccountService
public interface IAccountService extends IService<Account> {void addAccount(Account account);List<Account> findAll();}
AccountServiceImpl
@DS("master") // 方法中的@DS注解优先
@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements IAccountService {@Overridepublic void addAccount(Account account) {this.save(account);}@Override@DS("slave") // 填写组名, 会负载均衡// @DS("slave_1")public List<Account> findAll() {return this.list();}}
AccountMapper
public interface AccountMapper extends BaseMapper<Account> {}
AccountMapper.xml
<?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.zzhua.mapper.AccountMapper"><!-- 通用查询映射结果 --><resultMap id="BaseResultMap" type="com.zzhua.entity.Account"><id column="id" property="id" /><result column="nick_name" property="nickName" /></resultMap><!-- 通用查询结果列 --><sql id="Base_Column_List">id, nick_name</sql></mapper>
测试
访问:http://localhost:8080/account/createAccount?nickName=m1
,发现数据插入到了m_db数据库中
访问:http://localhost:8080/account/getAccounts
,发现查询的是s_db数据库