需求
实现在member模块中通过feign调用business模块,更新数据库的数据,如果成功都成功,如果失败都失败
seata 准备工作
下载安装seata
使用AT模式,所以要生成对应的sql
准备工作
member与business模块的curd
common模块
依赖
pom.xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
member模块
建立自己独立的库
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud_member?characterEncoding=UTF8&autoReconnect=true&serverTimezone=Asia/Shanghai
配置seata
bootstrap.properties
新增
seata.tx-service-group=train-group
# ????seata?????
seata.service.vgroup-mapping.train-group=default
# seata???????
seata.service.grouplist.default=127.0.0.1:8091
business模块
建立自己独立的库
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud_business?characterEncoding=UTF8&autoReconnect=true&serverTimezone=Asia/Shanghai
配置seata
bootstrap.properties
新增
seata.tx-service-group=train-group
# ????seata?????
seata.service.vgroup-mapping.train-group=default
# seata???????
seata.service.grouplist.default=127.0.0.1:8091
调用
member
feign
feign/BusinessFeign
@FeignClient("business")
public interface BusinessFeign {
@PutMapping("/business/update")
void update(User user);
}
service
service/UserService
@Service
public class UserService {
private static final Logger LOG = LoggerFactory.getLogger(UserController.class);
@Resource
BusinessFeign businessFeign;
@Resource
private UserMapper userMapper;
@GlobalTransactional
public void testSeata(User user) throws Exception{
LOG.info("seata全局事务ID: {}", RootContext.getXID());
userMapper.updateByPrimaryKeySelective(user);
businessFeign.update(user);
if (1 == 1) {
throw new Exception("测试异常");
}
}
}
controller
controller/UserController
@RestController
public class UserController {
@Resource
private UserService userService;
@PutMapping("/test-seata")
public String testSeata(@RequestBody User user) throws Exception {
userService.testSeata(user);
return "ok";
}
}
异常处理
controller/ControllerExceptionHandler
@ControllerAdvice
public class ControllerExceptionHandler {
private static final Logger LOG = LoggerFactory.getLogger(com.example.springCloud3.common.controller.ControllerExceptionHandler.class);
/**
* 所有异常统一处理
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Object exceptionHandler(Exception e) throws Exception {
LOG.info("seata全局事务ID: {}", RootContext.getXID());
// 如果是在一次全局事务里出异常了,就不要包装返回值,将异常抛给调用方,让调用方回滚事务
if (StrUtil.isNotBlank(RootContext.getXID())) {
throw e;
}
Map<String, Object> map = new HashMap<>();
LOG.error("系统异常:", e);
map.put("error",e.getMessage());
return map;
}
}
演示效果
调用前数据
调用失败情况
请求
数据库中的数据
member和business的数据库中的数据都都没有更改
事务回滚
调用成功情况
修改自己制造的异常
service/UserService
@GlobalTransactional
public void testSeata(User user) throws Exception{
LOG.info("seata全局事务ID: {}", RootContext.getXID());
userMapper.updateByPrimaryKeySelective(user);
businessFeign.update(user);
//自己制造异常
// if (1 == 1) {
// throw new Exception("测试异常");
// }
}
请求
数据库中的数据
member和business的数据库中的数据都成功更改
事务回滚
没有触发事务回滚
seate与sql存储
每次成功或失败后都会清除数据
service/UserService
增加延时器看效果Thread.sleep(10000);
@GlobalTransactional
public void testSeata(User user) throws Exception{
LOG.info("seata全局事务ID: {}", RootContext.getXID());
userMapper.updateByPrimaryKeySelective(user);
businessFeign.update(user);
//自己制造异常
Thread.sleep(10000);
// if (1 == 1) {
// throw new Exception("测试异常");
// }
}