官網
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