<?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>
spring:
autoconfigure:
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
datasource:
master:
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.52.130:3306/firstDB?useSSL=false&useUnicode=true&characterEncoding=utf8
type: com.alibaba.druid.pool.DruidDataSource
slave_1:
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.52.130:3306/secondDB?useSSL=false&useUnicode=true&characterEncoding=utf8
type: com.alibaba.druid.pool.DruidDataSource
#......省略
#以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
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 {
@Override
public 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 {
@Autowired
private SecondStudentService secondStudentService;
@Override
public 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 {
@Autowired
private FirstStudentMapper firstStudentMapper;
@Autowired
private FirstStudentService firstStudentService;
@Test
void name() {
firstStudentService.syncDataBase();
}
@Test
void 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 数据源