1. 双数据库创建
两个数据库各有一张表
2. yml中配置双数据库
下面的配置来源于mybatis-plus官网
spring:datasource:dynamic:primary: master #设置默认的数据源或者数据源组,默认值即为masterstrict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源datasource:master:url: jdbc:mysql://1.XX.xx.58:3306/mybatis_plus?serverTimezone=Asia/Shanghai&characterEncoding=utf-8&useSSL=falseusername: rootpassword: xxxdriver-class-name: com.mysql.cj.jdbc.Driverslave:url: jdbc:mysql://1.XX.xx.58:3306/hostDataBase?serverTimezone=Asia/Shanghai&characterEncoding=utf-8&useSSL=falseusername: rootpassword: xxxdriver-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 {@Overridepublic 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 调用侧
@Autowiredprivate EmployeeService employeeService;@GetMapping("/saveInfo")@ApiOperation(value = "Employer测试")/*** 如果涉及到多个数据源,则需要使用该注解*/@DSTransactionalpublic 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博客