首頁  >  文章  >  資料庫  >  MySQL嵌套事務所遇到的問題的程式碼實例詳解

MySQL嵌套事務所遇到的問題的程式碼實例詳解

黄舟
黄舟原創
2017-03-06 13:26:28976瀏覽

這篇文章主要介紹了MySQL嵌套事務所遇到的問題的相關資料,需要的朋友可以參考下

MySQL是支持嵌套事務的,但是沒多少人會這麼做的…. 前段時間在國外看到一些老外在爭論MySQL嵌套事務的場景必要性。 逗死我了, 這嵌套的鬼畜用法還有啥場景必要性。   跟以前的dba同事聊過, 得知,在任何場景下都不要使用MySQL嵌套的事務。

那麼使用MySQL巢狀交易會遇到什麼問題?

mysql> select * from ceshi; 
+------+ 
| n  | 
+------+ 
|  1 | 
+------+ 
1 row in set (0.00 sec) 
 
mysql> start transaction ; 
Query OK, 0 rows affected (0.00 sec) 
 
mysql> insert into ceshi values(2); 
Query OK, 1 row affected (0.00 sec) 
 
mysql> start transaction ; 
Query OK, 0 rows affected (0.00 sec) 
 
mysql> insert into ceshi values(3); 
Query OK, 1 row affected (0.00 sec) 
 
mysql> commit; 
Query OK, 0 rows affected (0.00 sec) 
 
mysql> rollback; 
Query OK, 0 rows affected (0.00 sec)


#雖然我在最後rollback回滾了,但是資料顯示是  1 2 3  .    原本大家以為我的事務雖然是嵌套的狀態,但感覺最後rollback回滾了,其實我們希望看到的結果是子事務執行成功,外層事務的失敗會回滾的。但事實不是這樣的,最後的結果是  1 2 3 .

#
+-----+ 
| n   | 
+-----+ 
|  1 | 
|  2 | 
|  3 | 
+-----+

當sql解釋器遇到start transaction 時候會觸發commit… ! !!   

begin_1  sql_1  

begin_1  sql_1  begin_2  sql_2  sql_3 commit_1  rollback_1  .

begin_2 被執行的時候, sql_1 已經就被提交了那麼sql_2 和sql_3 就被提交了.    這時候你再去rollback,一定用都沒有….    因為先前都提交完了,你能回滾啥…

前面說過在架構上一般很少很少有人會嵌套使用事務,但有時候不小心被嵌套了。 我們拿python的專案來說,首先我們使用裝飾器來實現事務的包裝, 接著資料處理def a() 和  def b() 函數都被事務被包裝起來, 單純的用a 和b 都沒關係,都是單事務。  如果 a 邏輯裡又呼叫 b, 那麼會發生什麼事?   對的,事務嵌套了…    我想這是絕大數業務開發都會遇到的問題。

那麼怎麼規避這風險?  可以加鎖呀….   設立一個全域鎖定,當子事務創建前會判斷鎖的狀態….

如果你是flask的框架,可以使用flask g 全域變數。  

如果是django框架, 那麼可以使用 thread local使用全域變數。

如果是tornado、gevent這種非同步io架構,可以使用 fd 做協程變數的關聯。

@decorator
def with_transaction(f, *args, **kwargs):
 
  db = connection.get_db_by_table("*")
  try:
    db.begin()
    ret = f(*args, **kwargs)
    db.commit()
  except:
    db.rollback()
    raise
  return ret
 
 
@with_transaction
def hide(self):
  '''订单不在app端显示'''
  if self.status not in OrderStatus.allow_deletion_statuses():
    raise OrderStatusChangeNotAllowed(self.status, OrderStatus.deleted)
...
 
 
@with_transaction
def change_receipt_info(self, address, name, phone):
  region = Region.get_by_address(address)
  ...

當我們去執行下面語句的時候,事務會被強制提交.   當然這裡前提是 autocommit = True 。

ALTER FUNCTION  
ALTER PROCEDURE  
ALTER TABLE  
BEGIN  
CREATE DATABASE  
CREATE FUNCTION  
CREATE INDEX  
CREATE PROCEDURE  
CREATE TABLE  
DROP DATABASE  
DROP FUNCTION  
DROP INDEX  
DROP PROCEDURE  
DROP TABLE  
UNLOCK TABLES  
LOAD MASTER DATA  
LOCK TABLES  
RENAME TABLE  
TRUNCATE TABLE  
SET AUTOCOMMIT=1  
START TRANSACTION


以上就是MySQL嵌套事務所遇到的問題的程式碼實例詳解的內容,更多相關內容請關注PHP中文網(www.php .cn)!

#########
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn