淺談一下ThinkPHP5.1實現事務嵌套的特性


前言:     

    在我們平時做的一個項目中,線上環境突然發現數據庫被鎖住。導致很多有關數據插入和修改的接口全都癱瘓,項目基於ThinkPHP5.1。報錯的時候,我們發現了一條sql錯誤日志,如下。

     根據錯誤信息提示,是說有一個事務回滾時沒有找到savepoint 的暫存點。所以問題應該是事務嵌套導致的,目前ThinkPHP5封裝的數據層方法是有對事務嵌套進行處理。而MYSQL到底支不支持事務嵌套呢?偽代碼如下。

     執行完后出現了操作1的數據真正寫入,只有操作2的數據回滾了。在第一個事務沒有提交或回滾時,再開啟第二個事務時,會自動提交第一個事務。 這明顯不符合心理預期,而且也無法回滾一部分操作。首先,調用多次begin的寫法,在MySQL里肯定是無法首先事務嵌套的。

    抱着疑問,我去網上也查了很多類似的問題。卻意外的發現關於“解決事務嵌套的方法”都如此的雷同,清一色的 “開啟事務時候使用單例,檢查事務是否存在”。(蒙圈……)

    繼續回到MYSQL是否支持事務嵌套,最后我了解到MySQL中有一個叫savepoint和rollback to的語句。於是我順手舉了個例子。

    上面有3張表,分別有不同的更新操作和最后的插入。但是最后只回滾到P1,執行完commit后,我發現只有p1位置的操作做了更新,后面的修改和插入全都沒生效。可能savepoint和rollback to語句並不能稱之為事務嵌套,也不能說MySQL是支持還是不支持事務嵌套。總之通過savepoint和rollback to,是可以用來達到一些事務嵌套特性的。

    根據我們項目的日志,我也試着復現一下,故意rollback to到一個不存在的點上,最后commit時發現,數據庫的第一條sql修改了,后面插入語句也添加成功了。

 

ThinkPHP5.1

    所以再回到ThinkPHP5框架實現的事務嵌套,於是我打開了框架的Connection抽象類。最主要的就是下面部分了。

1. 開啟事務。

    開啟事務的部分加了次數累加,只要在代碼塊中使用了transaction就會被記錄並疊加,當只有1時,才執行sql的begin,否則就savepoint記錄一個保存點。

2. 提交事務。

    判斷了只有等於1才對事務進行提交,也就是在代碼中最后面的commit才生效,使用一次減一次嵌套計數。initConnect方法主要是對分布式數據庫和單機對讀寫連接的判斷。

3. 回滾事務。

    回滾主要也是當計數等於1才讓sql執行rollback,否則(也就是嵌套了)就讓連接資源回滾到執行的保存點。它里面的就是使用的rollback to p1 語句的。

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM