西部数码主机 | 阿里云主机| 虚拟主机 | 服务器 | 返回乐道官网
当前位置: 主页 > 开发教程 > mysql教程 >

让人无语的MySQL嵌套事务

时间:2017-01-15 23:18来源:未知 作者:好模板 点击:
MySQL是支持嵌套事务的,但是没多少人会这么干的. 前段时间在国外看到一些老外在争论MySQL嵌套事务的场景必要性。 逗死我了, 这嵌套的鬼畜用法还有啥场景必要性。 跟以前的dba同事

MySQL是支持嵌套事务的,但是没多少人会这么干的…. 前段时间在国外看到一些老外在争论MySQL嵌套事务的场景必要性。 逗死我了, 这嵌套的鬼畜用法还有啥场景必要性。   跟以前的dba同事聊过, 得知,在任何场景下都不要使用MySQL嵌套的事务。

那么使用MySQL嵌套事务会遇到什么问题 ?

 
mysql> select * from ceshi;  
+------+  
|  n  |  
+------+  
|    1 |  
+------+  
1 rowin set (0.00 sec)  
  
mysql> starttransaction ;  
QueryOK, 0 rowsaffected (0.00 sec)  
  
mysql> insertintoceshivalues(2);  
QueryOK, 1 rowaffected (0.00 sec)  
  
mysql> starttransaction ;  
QueryOK, 0 rowsaffected (0.00 sec)  
  
mysql> insertintoceshivalues(3);  
QueryOK, 1 rowaffected (0.00 sec)  
  
mysql> commit;  
QueryOK, 0 rowsaffected (0.00 sec)  
  
mysql> rollback;  
QueryOK, 0 rowsaffected (0.00 sec)  

虽然我在最后rollback回滚了,但是数据显示是  1 2 3  .    原本大家以为我的事务虽然是嵌套的状态,但感觉最后rollback回滚了,其实我们希望看到的结果是 子事务执行成功,外层事务的失败会回滚的。  但事实不是这样的,最后的结果是  1 2 3 .  

 
# xiaorui.cc
 
+-----+  
| n    |  
+-----+  
|    1  |  
|    2  |  
|    3  |  
+-----+  

当sql解释器遇到 start transaction 时候会触发commit… !!!    

begin_1  sql_1  begin_2  sql_2  sql_3 commit_1  rollback_1  . 

begin_2 被执行的时候, sql_1 已经就被提交了, 当你再去执行commit_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.statusnot 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 。

 
ALTERFUNCTION    
ALTERPROCEDURE    
ALTERTABLE    
BEGIN    
CREATEDATABASE    
CREATEFUNCTION    
CREATEINDEX    
CREATEPROCEDURE    
CREATETABLE    
DROPDATABASE    
DROPFUNCTION    
DROPINDEX    
DROPPROCEDURE    
DROPTABLE    
UNLOCKTABLES    
LOADMASTERDATA    
LOCKTABLES    
RENAMETABLE    
TRUNCATETABLE    
SET AUTOCOMMIT=1    
STARTTRANSACTION    

END.

(责任编辑:好模板)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
热点内容