官网
AT模式:https://github.com/seata/seata/wiki/AT-Mode
流程解释:http://seata.io/zh-cn/docs/overview/what-is-seata.html
AT流程图解
https://www.cnblogs.com/smileIce/p/11200829.html
注意
1、表必须有主键。
2、截止到0.9版不支持联合主键。可以用自增id做主键+联合主键改为唯一键。
3、UNDO_LOG表每个数据库都创建,记录全局事务Xid+表名+执行前/后镜像 等信息用于回滚。
在全局事务的每个子事务执行时,一起本地提交UNDO_LOG表(和本地业务在同一个事务中)。
4 、AT模式下,Seata为全局事务涉及到的数据行在SeataServer中建立全局锁(表名+主键),写操作提交时需要先拿到此行数据的全局锁,在全局事务提交时才会释放全局锁。通过全局锁(表+主键)保证同一行数据要在一个全局事务完成后,其他全局事务才能写操作。
5、全局事务隔离性默认是读未提交。因为一个全局事务的每个子事务在执行后都是立即本地提交的,但是此时全局事务并未提交,而且还可能会回滚。但是此时其他查询会读到已经本地提交的数据。
官方的全局读已提交隔离性通过select for update申请全局锁实现
官方对隔离性的说明:https://github.com/seata/seata/wiki/AT-Mode
回滚实例,原代码逻辑解析,bug坑分析
https://blog.csdn.net/flyfhj/article/details/99456100
检验开始
AbstractUndoExecutor.java的dataValidationAndGoOn方法
protected boolean dataValidationAndGoOn(Connection conn) throws SQLException {
//数据修改前镜像
TableRecords beforeRecords = sqlUndoLog.getBeforeImage();
//数据修改后镜像
TableRecords afterRecords = sqlUndoLog.getAfterImage();
//如果修改前镜像=修改后镜像,说明数据没有变更,无须回滚
if (DataCompareUtils.isRecordsEquals(beforeRecords, afterRecords)) {
return false;
}
//查找当前镜像
TableRecords currentRecords = queryCurrentRecords(conn);
//如果当前镜像**不等于**修改后镜像,继续对比
if (!DataCompareUtils.isRecordsEquals(afterRecords, currentRecords)) {
//如果当前镜像**等于**修改前镜像,说明数据没有变更,无须回滚,否则为脏数据直接抛出异常
if (DataCompareUtils.isRecordsEquals(beforeRecords, currentRecords)) {
总结3点:
1、修改前镜像等于修改后镜像,说明数据没有变更,无须回滚
2、当前镜像等于修改后镜像,则说明当前数据需要进行回滚
3、当前镜像不等于修改后镜像且当前镜像等于修改前镜像,说明数据无变更,无须回滚
举例:
修改前镜像 | 修改后镜像 | 当前镜像 | 是否回滚 |
---|---|---|---|
5000 | 4700 | 5000 | 不回滚 |
5000 | 4700 | 4700 | 回滚 |
5000 | 5000 | *** | 不回滚 |
5000 | 4700 | 4400 | 脏数据&&不回滚 |
集成NACOS