第一步、导入依赖
<?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.tiger</groupId><artifactId>DoubleDataSource</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- 声明springboot的版本号 --><spring-boot.version>2.5.5</spring-boot.version></properties><!-- 引入springboot官方提供的所有依赖的版本号定义,如果项目中使用相关依赖,可以不必写版本号了--><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><!-- 引入springboot的web项目的依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 基于 mybatis plus 的dao层的相关依赖 start--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><!-- 德鲁伊启动器 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.6</version></dependency><!-- 数据库依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><!-- 基于 mybatis plus 的dao层的相关依赖 end--><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.3.2</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- springboot测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies></project>
第二步、yml文件
spring:autoconfigure:exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfiguredatasource:dynamic:primary: master #设置默认的数据源或者数据源组,默认值即为masterdatasource:master:username: rootpassword: rootdriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://192.168.52.130:3306/firstDB?useSSL=false&useUnicode=true&characterEncoding=utf8type: com.alibaba.druid.pool.DruidDataSourceslave_1:username: rootpassword: rootdriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://192.168.52.130:3306/secondDB?useSSL=false&useUnicode=true&characterEncoding=utf8type: com.alibaba.druid.pool.DruidDataSource#......省略#以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
第三步、mapper service serviceImpl
package com.tiger.DoubleDataSourceApp.mapper;import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tiger.DoubleDataSourceApp.pojo.Student;public interface FirstStudentMapper extends BaseMapper<Student> {
}
package com.tiger.DoubleDataSourceApp.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.tiger.DoubleDataSourceApp.pojo.Student;public interface FirstStudentService extends IService<Student> {
}
package com.tiger.DoubleDataSourceApp.service.impl;import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tiger.DoubleDataSourceApp.mapper.FirstStudentMapper;
import com.tiger.DoubleDataSourceApp.pojo.Student;
import com.tiger.DoubleDataSourceApp.service.FirstStudentService;
import org.springframework.stereotype.Service;@Service
@DS("master")
public class FirstStudentServiceImpl extends ServiceImpl<FirstStudentMapper, Student> implements FirstStudentService {
}
package com.tiger.DoubleDataSourceApp;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan(basePackages = "com.tiger.DoubleDataSourceApp.mapper")
public class DDSApplication {public static void main(String[] args) {SpringApplication.run(DDSApplication.class,args);}
}
如何在同一个方法中切换数据源?
DynamicDataSourceContextHolder.push("slave");//slave即数据源名称
//中间执行你的业务sql
DynamicDataSourceContextHolder.clear();
第四步、整合事务测试
package com.tiger.DoubleDataSourceApp.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.tiger.DoubleDataSourceApp.pojo.Student;import java.util.List;public interface SecondStudentService extends IService<Student> {boolean saveList(List<Student> list);
}
package com.tiger.DoubleDataSourceApp.service.impl;import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tiger.DoubleDataSourceApp.mapper.FirstStudentMapper;
import com.tiger.DoubleDataSourceApp.pojo.Student;
import com.tiger.DoubleDataSourceApp.service.FirstStudentService;
import com.tiger.DoubleDataSourceApp.service.SecondStudentService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;@Service
@DS("slave_1")
@Transactional(rollbackFor = Exception.class)
public class SecondStudentServiceImpl extends ServiceImpl<FirstStudentMapper, Student> implements SecondStudentService {@Overridepublic boolean saveList(List<Student> list) {boolean b = this.saveBatch(list);int i=1/0;return b;}
}
package com.tiger.DoubleDataSourceApp.service.impl;import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tiger.DoubleDataSourceApp.mapper.FirstStudentMapper;
import com.tiger.DoubleDataSourceApp.pojo.Student;
import com.tiger.DoubleDataSourceApp.service.FirstStudentService;
import com.tiger.DoubleDataSourceApp.service.SecondStudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;@Service
@DS("master")
public class FirstStudentServiceImpl extends ServiceImpl<FirstStudentMapper, Student> implements FirstStudentService {@Autowiredprivate SecondStudentService secondStudentService;@Overridepublic int syncDataBase() {List<Student> list = this.list();secondStudentService.saveList(list);return 0;}
}
package com.tiger.DoubleDataSourceApp.mapper;import com.tiger.DoubleDataSourceApp.pojo.Student;
import com.tiger.DoubleDataSourceApp.service.FirstStudentService;
import lombok.AllArgsConstructor;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class SencondStudentMapperTest {@Autowiredprivate FirstStudentMapper firstStudentMapper;@Autowiredprivate FirstStudentService firstStudentService;@Testvoid name() {firstStudentService.syncDataBase();}@Testvoid test1() {firstStudentMapper.insert(new Student(null,"张三",3));}
}
经过测试能够回滚.
mapper上也能加,加了代理的对象,就是对应的数据源,但是最好是在serviceImpl方法上加,可以做事务处理
需要注意的是,不能再两个不同数据源里加事务,事务只能对应一个数据源.
@Override@Transactional(rollbackFor = Exception.class)public int syncDataBase() {List<Student> list = this.list();System.out.println(list);DynamicDataSourceContextHolder.push("slave_1");List<Student> list1 = this.list();System.out.println(list1);DynamicDataSourceContextHolder.poll();DynamicDataSourceContextHolder.push("slave_1");List<Student> list2 = this.list();System.out.println(list2);DynamicDataSourceContextHolder.poll();DynamicDataSourceContextHolder.push("master");List<Student> list3 = this.list();System.out.println(list3);DynamicDataSourceContextHolder.clear();List<Student> list4 = this.list();System.out.println(list4);return 0;}
这样的结果,就是让这里面所有的都变成一个数据源
DynamicDataSourceContextHolder.poll();
DynamicDataSourceContextHolder.clear();
的区别
前者只是弹出当前数据源,然后使用标记的DS数据源
clear强制清楚本地数据源,直接用 master 数据源