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。
数据源分组
,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。@DS
(3.2.0+)。动态增加移除数据源
方案。多层数据源嵌套切换
。(ServiceA >>> ServiceB >>> ServiceC)。基于seata的分布式事务方案
。本地多数据源事务方案(不能和原生spring事务混用)
只做 切换数据源
这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何CRUD。以下划线 _ 分割的数据源 首部 即为组的名称
,相同组名称的数据源会放在一个组下
。可以是组名
,也可以是具体数据源名称
。组名则切换时采用负载均衡算法切换
。默认的数据源名称为 master
,你可以通过 spring.datasource.dynamic.primary
修改。方法上的注解优先于类上注解
。不支持继承接口上的DS
。<dependency>
<groupId>com.baomidougroupId>
<artifactId>dynamic-datasource-spring-boot-starterartifactId>
<version>${version}version>
dependency>
以下会配置一个默认库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:
@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;
导入mybatis-plus(不一定要用mybatis-plus,只是因为懒得自己写mapper.xml文件) 和 dynamic-datasource 的依赖
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.8.RELEASEversion>
<relativePath/>
parent>
<groupId>com.zzhuagroupId>
<artifactId>sdynamic-datasource-demoartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springboot-demoname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.5.3version>
dependency>
<dependency>
<groupId>p6spygroupId>
<artifactId>p6spyartifactId>
<version>3.9.1version>
dependency>
<dependency>
<groupId>org.freemarkergroupId>
<artifactId>freemarkerartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>dynamic-datasource-spring-boot-starterartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version> 2.7.0version>
dependency>
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>swagger-bootstrap-uiartifactId>
<version>1.9.6version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
#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
开启mybatis的mapper接口扫描
@SpringBootApplication
@MapperScan("com.zzhua.mapper")
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
}
@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();
}
}
public interface IAccountService extends IService<Account> {
void addAccount(Account account);
List<Account> findAll();
}
@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();
}
}
public interface AccountMapper extends BaseMapper<Account> {
}
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数据库