Spring Cloud Alibaba(三)Seata
Seate是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
Seata将为用户提供了AT、TCC、SAGA和XA事务模型,为用户打造一站式的分布式解决方案。
项目场景搭建
逻辑约定
图书借阅流程:调用图书服务书籍数量减1->添加借阅记录->调用用户服务可借阅数减1
约束:每个用户最多同时借阅2本不用的书,图书馆中的所有书都有且仅有3本
数据库修改
用户表
添加字段book_count记录用户可借阅书籍数量
书籍表
添加字段count记录书籍剩余数量
服务修改
borrow-service
dao层
BorrowMapper.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Mapper public interface BorrowMapper {
List<Borrow> getBorrow(Long uid, Long bid);
int addBorrow(Long uid, Long bid); }
|
BorrowMapper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.test.dao.BorrowMapper"> <select id="getBorrow" resultType="com.test.entity.Borrow"> SELECT * FROM borrow_info <where> <if test="uid != null"> uid = #{uid}</if> <if test="bid != null"> and bid = #{bid}</if> </where> </select> <insert id="addBorrow" parameterType="com.test.entity.Borrow"> INSERT INTO borrow_info (id, uid, bid) VALUES (null, #{uid}, #{bid}) </insert> </mapper>
|
Service层
BorrowService.java
1 2 3 4 5 6 7 8 9
| public interface BorrowService { UserBorrowDetail getBorrowByUser(Long uid);
BookBorrowDetail getBorrowByBook(Long bid);
BorrowDetail getBorrow(Long uid, Long bid); boolean borrow(Long uid, Long bid); }
|
BorrowServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @SuppressWarnings("AliControlFlowStatementWithoutBraces") @Service @Slf4j public class BorrowServiceImpl implements BorrowService { @Resource BorrowMapper borrowMapper; @Resource UserService userService; @Resource BookService bookService;
@Override public boolean borrow(Long uid, Long bid) { User user = userService.getUserById(uid); log.info("" + user); if (user.getCount() < 1) throw new RuntimeException("用户借阅数达到上限"); Book book = bookService.getBookById(bid); if (book.getCount() < 1) throw new RuntimeException("图书数量不足"); if (!bookService.borrow(bid)) throw new RuntimeException("调用图书服务出错"); if (!borrowMapper.getBorrow(uid, bid).isEmpty()) throw new RuntimeException("用户已经借阅过此书"); if (borrowMapper.addBorrow(uid, bid) < 1) throw new RuntimeException("借阅信息添加失败"); if (!userService.borrow(bid)) throw new RuntimeException("调用用户服务出错"); return true; } }
|
Controller层
BorrowController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Api(tags = "UserController", description = "用户信息管理") @RestController
public class UserController { @Resource UserService userService;
public static final Logger logger = LoggerFactory.getLogger(UserController.class);
@ApiOperation("图书借阅") @PostMapping(value = "/{uid}/{bid}", produces = "application/json;charset=UTF-8") public JSONObject borrow(@PathVariable("uid") @ApiParam("用户id") Long uid, @PathVariable("bid") @ApiParam("图书id") Long bid) { boolean result = borrowService.borrow(uid, bid); JSONObject jsonObject = new JSONObject(); if (result) { jsonObject.put("code", 200); jsonObject.put("success", true); jsonObject.put("message", "借阅成功"); return jsonObject; } jsonObject.put("code", 100); jsonObject.put("success", false); jsonObject.put("message", "借阅失败"); return jsonObject; } }
|
分布式事务解决方案
XA-2PC
XA是一种典型的两阶段提交(2PC,Two-phase commit protocal)
两阶段提交协议 ,它分为两个阶段,一个是准备一个是提交。
整个过程的参与者一共有两个角色,一个是事务的执行者,一个是事务的协调者,实际上整个分布式事务的运作都需要依靠协调者来维持。
为了实现二阶段提交算法的成立基于以下假设:
- 该分布式系统中,存在一个节点作为协调者(Coordinator),其他节点作为参与者(Cohorts),节点之间可以进行网络通信
- 所有节点都采用预写式日志,且日志被写入后即保持在可靠的存储设备上,即使损坏不会导致日志数据的消失
- 所有节点不会永久性损坏,即使损坏后仍然可以恢复
第一阶段(投票阶段)
1、协调者节点向所有参与者节点询问是否可以执行提交操作(vote),并开始等待各参与者节点的响应
2、参与者节点执行询问发起为止的所有事务操作,并将Undo信息和Redo信息写入日志。(注意:若成功这里其实每个参与者已经执行了事务操作)
3、各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个“同意”消息;如果参与者节点的事务操作失败实际执行失败,则它返回一个“中止”消息
第二阶段(提交执行阶段)
当协调者节点从所有参与者节点获得响应消息都为“同意”时:
- 协调者节点向所有参与者节点发出”正式提交(commit)”的请求。
- 参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
- 参与者节点向协调者节点发送”完成”消息。
- 协调者节点受到所有参与者节点反馈的”完成”消息后,完成事务。
如果任一参与者节点在第一阶段返回的响应消息为”中止”,或者 协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:
- 协调者节点向所有参与者节点发出”回滚操作(rollback)”的请求。
- 参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。
- 参与者节点向协调者节点发送”回滚完成”消息。
- 协调者节点受到所有参与者节点反馈的”回滚完成”消息后,取消事务。
3PC
TTC
SAGA