4.0.0
com.tiger
DoubleDataSource
1.0-SNAPSHOT
17
17
UTF-8
2.5.5
org.springframework.boot
spring-boot-dependencies
${spring-boot.version}
pom
import
org.springframework.boot
spring-boot-starter-web
com.baomidou
mybatis-plus-boot-starter
3.5.2
com.alibaba
druid-spring-boot-starter
1.2.6
mysql
mysql-connector-java
5.1.47
com.baomidou
dynamic-datasource-spring-boot-starter
3.3.2
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-test
test
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 {
}
package com.tiger.DoubleDataSourceApp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.tiger.DoubleDataSourceApp.pojo.Student;
public interface FirstStudentService extends IService {
}
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 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 {
boolean saveList(List 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 implements SecondStudentService {
@Override
public boolean saveList(List 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 implements FirstStudentService {
@Autowired
private SecondStudentService secondStudentService;
@Override
public int syncDataBase() {
List 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 list = this.list();
System.out.println(list);
DynamicDataSourceContextHolder.push("slave_1");
List list1 = this.list();
System.out.println(list1);
DynamicDataSourceContextHolder.poll();
DynamicDataSourceContextHolder.push("slave_1");
List list2 = this.list();
System.out.println(list2);
DynamicDataSourceContextHolder.poll();
DynamicDataSourceContextHolder.push("master");
List list3 = this.list();
System.out.println(list3);
DynamicDataSourceContextHolder.clear();
List list4 = this.list();
System.out.println(list4);
return 0;
}
这样的结果,就是让这里面所有的都变成一个数据源
DynamicDataSourceContextHolder.poll();
DynamicDataSourceContextHolder.clear();
的区别
前者只是弹出当前数据源,然后使用标记的DS数据源
clear强制清楚本地数据源,直接用 master 数据源