PHP系統聲明式事務處理
1.數據庫事務
事務(Transaction)是并發控制的基本單位。所謂的事務,它是一個操作序列,這些操作要么都執行,要么都不執行,它是一個不可分割的工作單位。例如,銀行轉賬工作:從一個賬號扣款并使另一個賬號增款,這兩個操作要么都執行,要么都不執行。所以,應該把它們看成一個事務。事務是數據庫維護數據一致性的單位,在每個事務結束時,都能保持數據一致性。
事務具有以下4個基本特征:
● Atomic(原子性):事務中包含的操作被看做一個邏輯單元,這個邏輯單元中的操作要么全部成功,要么全部失敗。
● Consistency(一致性):只有合法的數據可以被寫入數據庫,否則事務應該將其回滾到最初狀態。
● Isolation(隔離性):事務允許多個用戶對同一個數據進行并發訪問,而不破壞數據的正確性和完整性。同時,并行事務的修改必須與其他并行事務的修改相互獨立。
● Durability(持久性):事務結束后,事務處理的結果必須能夠得到固化。
2.實現數據庫事務管理的方式
2.1 編碼式事務
在代碼中顯式調用beginTransaction()、commit()、rollback()等事務管理相關方法就是編碼式事務管理。
編碼式事務管理需要程序員在具體的業務代碼中顯式調用事務管理的相關方法,并顯式地根據各種條件來判斷是提交還是回滾。這種方式在業務簡單的系統中還可應付,對于業務復雜的系統可能會因為少了某些條件判斷導致錯誤的提交或回滾,尤其對于業務需求變動極其頻繁的系統可能會因為判斷條件沒有及時根據業務的調整而修改而導致錯誤的提交和回滾。
由于編碼式事務存在需要將事務管理與業務邏輯代碼耦合,并且難以判斷或及時更新回滾條件,甚至出現意料之外的事務嵌套等原因,因此不推薦使用編碼式方式管理事務。
2.2 聲明式事務
TP系統的聲明式事務管理機制在底層是建立在TP框架的行為擴展機制之上的。其實質是在控制器的目標方法執行前開啟事務,在執行完控制器的目標方法之后根據實際情形提交或回滾事務。
聲明式事務最大的優點就是不需要在具體的業務邏輯代碼中攙雜事務管理的代碼,只需在模塊配置中聲明需要開啟事務管理的方法,即可將事務運用到業務邏輯中。
3.TP項目的聲明式事務處理機制的實現
1)在系統常量配置中增加兩個常量:
// 開啟數據庫事務 define('DB_TRANS_ENABLE', true); // 數據庫事務全局標志 define('DB_TRANS_VAR', 'tx_comment');
2)在BaseModel中重載TP框架的Model類中的add、addAll、delete、execute、save方法
具體可查看相關代碼。
3)在MyActionBeginBehavior的run方法中根據系統全局事務開關和模塊配置判斷是否開啟數據庫事務
// 開啟數據庫事務 by 凡墻<jihaoju@qq.com> 2015.09.14 18:05 $db_trans_enable = C('DB_TRANS_ENABLE'); if(defined('DB_TRANS_ENABLE') && DB_TRANS_ENABLE && is_array($db_trans_enable) && in_array(strtolower(CONTROLLER_NAME . '.' . ACTION_NAME), $db_trans_enable)) { env(DB_TRANS_VAR, true); M()->startTrans(); }
4)在MyActionEndBehavior的run方法中根據系統全局事務開關、模塊配置以及環境變量DB_TRANS_VAR的值判斷是否提交事務
// 處理數據庫事務 by 凡墻<jihaoju@qq.com> 2015.09.14 18:05 $db_trans_enable = C('DB_TRANS_ENABLE'); if(defined('DB_TRANS_ENABLE') && DB_TRANS_ENABLE && is_array($db_trans_enable) && in_array(strtolower(CONTROLLER_NAME . '.' . ACTION_NAME), $db_trans_enable)) { $tx_commit = env(DB_TRANS_VAR); if ($tx_commit === false) { // 回滾 M()->rollback(); } else { // 提交事務 M()->commit(); } }
5)強制回滾
在需要強制回滾的代碼處將環境變量 DB_TRANS_VAR 的值設為 false,則系統將在目的方法結束后回滾。
4.存在的問題
4.1 數據庫讀寫分離
數據庫讀寫分離后,按TP框架的機制,一次請求將至少創建兩個數據庫連接,因此目前的聲明式事務實現機制需要針對讀連接和寫連接分別根據需要管理事務。
4.2 事務控制的細度
和編碼式事務相比,聲明式事務的最細粒度只能浸入到控制器的方法級別,沒法做到像編碼式事務那樣可以浸入到代碼塊級別,甚至無法做到對非控制器的方法的事務管理。
待擴展。
4.3 事務對數據的影響
幻讀phantom read:事務1讀取記錄時事務2增加了記錄并提交,事務1再次讀取時可以看到事務2新增的記錄;
不可重復讀unrepeatable read:事務1讀取記錄時,事務2更新了記錄并提交,事務1再次讀取時可以看到事務
修改后的記錄;
臟讀dirty read:事務1更新了記錄,但沒有提交,事務2讀取了更新后的行,然后事務T1回滾,現在T2讀取無效。
幻讀、不可重復讀、臟讀等問題可通過數據庫的事務隔離級別解決,待優化。
需要注意的是,若在數據模型層對數據做了緩存處理,系統開啟事務后可能導致“臟數據”的問題,因此對于一些重要數據字段的讀寫不能依賴于緩存中的數據。
4.4 分布式事務
數據庫分庫分表或系統采用微服務架構后將出現分布式事務問題。
待研究。