1. 程式人生 > >簡單聊聊事務補償機制

簡單聊聊事務補償機制

假設有如下的業務流程,使用者1給使用者2轉賬100元:

 

 轉賬服務需要執行如下操作:

第1步. 在資料庫連線1上執行:update 使用者表 set (使用者1的餘額) = (使用者1的餘額)- 100;

第2步. 在資料庫連線2上執行:update 使用者表 set (使用者2的餘額) = (使用者2的餘額)+ 100;

可能的問題:

1:第1步操作過程中,資料庫1掛了,轉賬服務無法得知對使用者1的扣款操作是否成功;

2:第1步操作成功,第2步操作失敗,轉賬服務回滾第1步的操作時,資料庫1掛了;

3:第1步操作成功,第2步操作過程中,資料庫2掛了,轉賬服務無法得知是否成功給使用者2加了錢;

 

基於上面的問題,產生了如下的資料庫設計:

轉賬流程變成了如下步驟:

第1步:

    轉賬服務生成一個事務號,全域性唯一;

第2步:轉賬服務在資料庫1上執行事務:

    開始事務:

        update 使用者表 set (使用者1的餘額) = (使用者1的餘額)- 100;

        insert 事務表 (事務號,成功)

    結束事務:

第3步:轉賬服務在資料庫2上執行事務:

    開始事務:

        update 使用者表 set (使用者2的餘額) = (使用者2的餘額)+ 100;

        insert 事務表 (事務號,成功)

    結束事務:

 

這樣做的好處

    當操作使用者1的賬戶失敗時,轉賬服務可以通過再次查詢資料庫1的事務表來判斷操作是否成功;

    當操作使用者2的賬戶失敗時,轉賬服務可以通過再次查詢資料庫2的事務表來判斷操作是否成功;

接下來的問題:

    當轉賬服務更新使用者1的賬戶成功後,接下來轉賬服務更新使用者2的賬戶之前,轉賬服務自己掛了;

    這時,使用者1被扣了100,但是使用者2沒多出來100,資料不一致;

 

新的資料庫設計產生了,如下:

    

 

接下來的操作步驟變成了這樣:

轉賬服務的操作:

    第1步:生成全域性唯一事務號;生成事務號對應的時間戳;

    第2步:在回滾庫的日誌表中插入---“事務號開始”的操作;

    第3步:在回滾庫的日誌表插入---“扣除使用者1的賬戶100元“的操作;

    第4步:在資料庫1上執行事務:

        開始事務:

            update 使用者表 set (使用者1的餘額) = (使用者1的餘額)- 100;

            insert 事務表 (事務號,成功)

        結束事務:

    第5步:在回滾庫的日誌表插入---“增加使用者2的賬戶100元”的操作;

    第6步:在資料庫2上執行事務:

        開始事務:

            update 使用者表 set (使用者2的餘額) = (使用者2的餘額)+ 100;

            insert 事務表 (事務號,成功)

        結束事務:


    第7步:在回滾庫的日誌表插入---“事務號結束”的操作;

 

回滾服務的操作:

    假設轉賬超時時間是1小時;

    定期檢查回滾庫中的回滾日誌表;

    如果事務號對應結束,則忽略;

    如果事務號沒有結束,但是事務沒超時,也忽略;

    如果事務號沒有結束,事務超時,則按照回滾日誌,反向操作,對事務進行補償,補償步驟如下:

        第1步:對使用者2進行事務補償,檢查資料庫2的使用者2的事務是否成功;

        第2步:如果成功,則認為事務完成,在事務回滾日誌表中將這次事務標識為成功;並跳到“結束步驟”;

        第3步:對使用者1進行事務補償,檢查資料庫1的使用者1的事務是否成功;

        第4步:如果成功,則執行如下事務:

            開始事務

                update 使用者表 set (使用者1的餘額) = (使用者1的餘額)+ 100;

                update 事務表 (事務號,回滾成功);

            結束事務

        第5步:在事務回滾日誌表將這次事務標識為成功;

        結束步驟

 

 結束哈;