一、约定
- 本框架只做 切换数据源 这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何CRUD。
- 配置文件所有以下划线 _ 分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。
- 切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。
- 默认的数据源名称为 master ,你可以通过 spring.datasource.dynamic.primary 修改。
- 方法上的注解优先于类上注解。
- 强烈建议只在service的类和方法上添加注解,不建议在mapper上添加注解。
二、用法
使用 @DS 切换数据源
@DS
可以注解在方法上和类上,同时存在方法注解优先于类上注解。
强烈建议只注解在service实现上。
三、源码示例
准备两个数据库:day27
和quartz
,day27
库下查user
表,quartz
库下查询quartz_user
表。
3.1 pom依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.2.1</version>
</dependency>
参考完整pom文件:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lsh</groupId>
<artifactId>dynamic-datasource</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- SpringBoot整合Mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<!--JPA-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!--lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
</dependency>
<!-- 阿里巴巴数据库连接池Druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.1</version>
</dependency>
<!-- aspectj -->
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.3</version>
</dependency>
<!-- aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--动态数据源插件-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2 yml配置文件
application.yml :
spring:
profiles:
active: test
application-test.yml :
spring:
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
master:
url: jdbc:mysql://localhost:3306/day27?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF8
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
slave_1:
url: jdbc:mysql://localhost:3306/quartz?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF8
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
logging:
level:
com.baomidou.dynamic: debug
3.3 实体类
@Data
@Entity
@Table(name = "user")
public class Day27User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
}
@Data
@Entity
@Table(name = "quartz_user")
public class QuartzUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
}
3.4 持久层使用JPA
Repository
public interface Day27UserRepository extends JpaRepository<Day27User,Integer> {
}
public interface QuartzUserRepository extends JpaRepository<QuartzUser,Integer> {
}
ServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
Day27UserRepository day27UserRepository;
@Autowired
QuartzUserRepository quartzUserRepository;
@Override
@DS("master")
public List<Day27User> findDay27User(){
List<Day27User> all = day27UserRepository.findAll();
return all;
}
@Override
@DS("slave_1")
public List<QuartzUser> findQuartzUser(){
List<QuartzUser> all = quartzUserRepository.findAll();
return all;
}
}
测试类
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceTest {
@Autowired
UserService userService;
@Test
public void test1(){
List<Day27User> day27User = userService.findDay27User();
day27User.forEach(System.out::println);
}
@Test
public void test2(){
List<QuartzUser> quartzUser = userService.findQuartzUser();
quartzUser.forEach(System.out::println);
}
}
多数据源可行。
3.5 持久层使用MyBatis
Mapper接口
@Mapper
public interface Day27UserMapper {
@Select("SELECT * FROM user")
List<Day27User> findAll();
}
@Mapper
public interface QuartzUserMapper {
@Select("SELECT * FROM quartz_user")
List<QuartzUser> findAll();
}
ServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
Day27UserRepository day27UserRepository;
@Autowired
QuartzUserRepository quartzUserRepository;
@Resource
Day27UserMapper day27UserMapper;
@Resource
QuartzUserMapper quartzUserMapper;
@Override
@DS("master")
public List<Day27User> findDay27User(){
List<Day27User> all = day27UserRepository.findAll();
return all;
}
@Override
@DS("slave_1")
public List<QuartzUser> findQuartzUser(){
List<QuartzUser> all = quartzUserRepository.findAll();
return all;
}
@Override
@DS("master")
public List<Day27User> findDay27UserByMyBatis() {
return day27UserMapper.findAll();
}
@Override
@DS("slave_1")
public List<QuartzUser> findQuartzUserByMyBatis() {
return quartzUserMapper.findAll();
}
}
测试类
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceTest {
@Autowired
UserService userService;
@Test
public void test1(){
List<Day27User> day27User = userService.findDay27User();
day27User.forEach(System.out::println);
}
@Test
public void test2(){
List<QuartzUser> quartzUser = userService.findQuartzUser();
quartzUser.forEach(System.out::println);
}
@Test
public void test3(){
List<Day27User> day27User = userService.findDay27UserByMyBatis();
day27User.forEach(System.out::println);
}
@Test
public void test4(){
List<QuartzUser> quartzUser = userService.findQuartzUserByMyBatis();
quartzUser.forEach(System.out::println);
}
}
Demo整体结构:
可以看出,无论持久层使用的是JPA还是MyBatis都是可以切换数据源的。
四、手动切换数据源
通过查询源码分析:
除了使用@DS
注解的方式来切换数据源,还可以通过DynamicDataSourceContextHolder
这个类手动的来进行数据源切换。
//切换数据源
DynamicDataSourceContextHolder.push("savle_2");
//查看当前数据源
DynamicDataSourceContextHolder.peek();
源码
项目源码:https://gitee.com/L1692312138/dynamic-data-source
自定义注解+切面实现多数据源切换:配置多数据源及数据源AbstractRoutingDataSource切换原理分析
数据源插件地址:https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter