1. 双数据库创建
两个数据库各有一张表
2. yml中配置双数据库
下面的配置来源于mybatis-plus官网
spring:
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
master:
url: jdbc:mysql://1.XX.xx.58:3306/mybatis_plus?serverTimezone=Asia/Shanghai&characterEncoding=utf-8&useSSL=false
username: root
password: xxx
driver-class-name: com.mysql.cj.jdbc.Driver
slave:
url: jdbc:mysql://1.XX.xx.58:3306/hostDataBase?serverTimezone=Asia/Shanghai&characterEncoding=utf-8&useSSL=false
username: root
password: xxx
driver-class-name: com.mysql.cj.jdbc.Driver
3. Mapper和Service
3.1 两个表对应的结构体
表 SPF_Require_Vehicle 对应的结构体
@TableName("SPF_Require_Vehicle")
@Data
public class Employee {
/**
* 指定主键名称为SPF_uid, 类型为自增,即数据库的字段必须是auto_increment
*/
@TableId(value = "SPF_UID", type = IdType.AUTO)
private Long id;
/**
* 指定数据库中对应的字段是 Part_PartSap
*/
@TableField("Part_PartSap")
private String partSap;
@TableField("Part_PlateSap")
private String plateSap;
@TableField("SPF_Name")
private String name;
/**
* 逻辑删除
*/
@TableLogic(value = "0", delval = "1")
@TableField("IsActvie")
private Boolean active;
@TableField("gender")
private SexEnum gender;
}
表Employer对应的结构体
@Data
@TableName("Employer")
public class EmployeerDO {
@TableId(value = "SPF_Id", type = IdType.AUTO)
private Long id;
@TableField("SPF_Name")
private String name;
@TableField("SPF_Age")
private int age;
@TableLogic(value = "0", delval = "1")
@TableField("IsActive")
private Boolean active;
}
3.2 两个Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
/**
* 手写语句实现分页查询
* @param page 拦截器使用,当前sql中不需要
* @param employee 查询对象
* @return 查询结果
*/
Page<Employee> getEmployeeInfoByPage(@Param("page") Page<Employee> page, @Param("employee") Employee employee);
}
public interface EmployerMapper extends BaseMapper<EmployeerDO> {
}
3.3 两个service
@Service
/**
* 指明当前service处理的是master数据库
*/
@DS("master")
@Transactional(rollbackFor = Exception.class)
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
@Override
public List<Employee> getEmployeeInfoByPage(Employee employee) {
Page<Employee> page = new Page<>(1, 3);
Employee e1 = new Employee();
e1.setName("wangshun");
this.baseMapper.getEmployeeInfoByPage(page, e1);
return page.getRecords();
}
}
@Service
/**
* 当前service使用的是slave数据库
*/
@DS("slave")
@Transactional(rollbackFor = Exception.class)
public class EmployerServiceImpl extends ServiceImpl<EmployerMapper, EmployeerDO> implements EmployerService {
}
3.4 调用侧
@Autowired
private EmployeeService employeeService;
@GetMapping("/saveInfo")
@ApiOperation(value = "Employer测试")
/**
* 如果涉及到多个数据源,则需要使用该注解
*/
@DSTransactional
public void saveEmployerInfo() {
EmployeerDO employeerDO = new EmployeerDO();
employeerDO.setAge(25);
employeerDO.setName("zhangsan");
Employee employee = new Employee();
employee.setGender(SexEnum.SEX_FEMALE);
// 该项为必填项,此处插入抛出异常,整个事务回滚
//employee.setPartSap("xxxxx-yy");
employee.setPlateSap("yyyyy-xx");
employee.setName("111111111");
this.employerService.save(employeerDO);
this.employeeService.save(employee);
}
@GetMapping("/saveEmployee")
@ApiOperation(value = "Employee测试")
/**
* 单个service,使用传统事务即可
*/
@Transactional(rollbackFor = Exception.class)
public void testEmployee() {
Employee employee = new Employee();
employee.setGender(SexEnum.SEX_FEMALE);
employee.setPartSap("xxxxx-yy");
employee.setPlateSap("yyyyy-xx");
employee.setName("111111111");
this.employeeService.save(employee);
// 事务会回滚
int tmp = 1/0;
this.employeeService.getEmployeeInfoByPage(null);
}
4. @DSTransactional
该注解和@Transaction的区别在于: 当一个函数中同时操作多个数据源时,即有多个service,则需要使用@DSTransactional 注解; 如果一个函数中操作的是同一个数据源,即只有一个service,则只需要使用 @Transactional
见 @Transactional和@DS避免数据源冲突的解决方案(提供gitee源码)_@dstransactional_一个资深码农的博客-CSDN博客