如何設計一張事件記錄流水錶(版本2)
在設計完 版本1的事件記錄表 後,大家就開始馬不停蹄寫程式碼去新增事件記錄資料。
流水ID id |
物件ID obj_id |
系統編碼 sys_code |
網點編碼 area_code |
操作者工號 operator_id |
源狀態 source_status |
事件編碼 event_code |
事件描述 event_desc |
目標狀態 target_status |
建立時間 create_time |
123456 | A111 | TEST_SYSTEM | XXX | 0123777 | 初始 | 001 | 列印 | 列印完成 | 2018-09-06 18:33:35 |
123457 | A111 | TEST_SYSTEM | QQQ | 0123666 | 列印完成 | 002 | 核銷 | 核銷完成 | 2018-09-07 12:05:43 |
改進:
在記錄事件的源狀態StateA時,一開始的做法是獲取其他業務資料表中某物件的當前狀態,來設定事件記錄表的源狀態。但在一些業務場景下,對於同一個事件編碼event_code,雖然目標狀態StateB是一樣的,但是源狀態StateA會有很多種情況,此時如果通過業務資料表的當前狀態來設定源狀態的值,會十分繁瑣,而且業務程式碼上需要知道當前狀態,不夠透明。
基於上面情況,我們不再從其他業務資料表中獲取某物件的當前狀態,而是依賴於事件記錄表前後的資料,從版本1的表中,可看到,在按照建立時間排序的前提下,ID為123457的源狀態(列印完成),就是上一條記錄ID為123456的目標狀態(目標狀態)。所以想要設定某物件的源狀態,只要找到該物件在事件記錄表中的上一條記錄的目標狀態即可。
但這種方案,嚴重依賴於上一條記錄,當有多個節點同時都往這個事件記錄表插入資料時,要對這“上一條記錄”的資料進行鎖定,需要採用分散式鎖或者資料庫鎖的機制。
再次改進:
認真想想,由於事件記錄表是按照物件做動作時按時間順序插入的,只要保證時間順序,其實可以不需要記錄源狀態,每條資料的目標狀態,也相當於它上一條資料的源狀態
流水ID id |
物件ID obj_id |
系統編碼 sys_code |
網點編碼 area_code |
操作者工號 operator_id |
事件編碼 event_code |
事件描述 event_desc |
目標狀態 target_status |
建立時間 create_time |
123456 | A111 | TEST_SYSTEM | XXX | 0123777 | 001 | 列印 | 列印完成 | 2018-09-06 18:33:35 |
123457 | A111 | TEST_SYSTEM | QQQ | 0123666 | 002 | 核銷 | 核銷完成 | 2018-09-07 12:05:43 |
由於事件記錄表本身的時間順序的特性,所以版本2的表基本可以滿足我們記錄物件全生命週期的需求。還是版本1的需求,比如我們想知道物件A111從列印完成狀態到核銷完成狀態所花費的時間,用sql更容易就實現了:
開始時間:
SELECT create_time AS begin_time FROM db_event_report WHERE obj_id = 'A111' AND target_status = '列印完成';
結束時間:
SELECT create_time AS end_time FROM db_event_report WHERE obj_id = 'A111' AND target_status = '核銷完成';
然後將上面兩條sql查詢出來的begin_time和end_time套入以下sql函式,即可算出相隔的分鐘數
SELECT TIMESTAMPDIFF(MINUTE, begin_time, end_time);
至此,我們的事件記錄流水錶設計結束。