学习链接
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 #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
master:
url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
slave_1:
url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
slave_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 {
@Autowired
private 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: root
spring:
datasource:
dynamic:
primary: master
strict: true
datasource:
master:
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: root
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
min-idle: 2
max-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=true
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-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 {
@Autowired
private 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 {
@Override
public 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数据库