python django事务transaction源码分析详解
pythonDjango事务
网上关于django1.6的事务资料很多,但是1.8的却搜不到任何资料,自己要用的时候费了不少劲就是不行,现在记下要用的人少走弯路version:Django1.8事务官方文档事务中文文档里面介绍很多方法,不一一赘述,按照文档即可,下面只分析下atomic方法的源码按照官方文档transaction.atomic有两种用法装饰器和上下文管理器
#atomic()方法 #fromdjango.dbimporttransaction ################### #atomic() ################### defatomic(using=None,savepoint=True):#装饰器和上下文管理器必须.()调用方法,因为真正的处理是该方法返回的实例,不是该方法本身 ifcallable(using): returnAtomic(DEFAULT_DB_ALIAS,savepoint)(using) #Decorator:@atomic(...)orcontextmanager:withatomic(...):... else: returnAtomic(using,savepoint) ########################################## #Atomic类省略了非核心内容 ############################################ classAtomic(ContextDecorator): def__init__(self,using,savepoint): self.using=using self.savepoint=savepoint def__enter__(self): connection=get_connection(self.using) sid=connection.savepoint()#进入with创建一个保存点 #.............do def__exit__(self,exc_type,exc_value,traceback): ifconnection.in_atomic_block: #do............. ifsidisnotNone: try: connection.savepoint_commit(sid)#提交事务 exceptDatabaseError: try: connection.savepoint_rollback(sid)#捕获数据库异常回滚 connection.savepoint_commit(sid) exceptError: connection.needs_rollback=True raise ##还有一段代码是exec_type收到其他程序异常时候全局回滚,此处省略 #do................. ############################### #ContextDecorator ################################# classContextDecorator(object): def__call__(self,func): definner(*args,**kwargs): withself:#把函数放进self的with上下文管理器,效果with相同,只是控制细粒度不同 returnfunc(*args,**kwargs) returninner
pythonMySQLdb
classTran(): def__init__(self,conn=None,close=True): ifconnisNone:#创建数据库链接 print'init' self.conn=conn_tbkt() self.cur=self.conn.cursor() self.sql=[] def__enter__(self):#上下文管理器返回sql语句列表withTran('tbkt_pxb')assqls: print'enter' returnself.sql#sql.append('select1') def__exit__(self,exc_type,exc_val,exc_tb): print'exit' try: printself.sql#执行sql forsinself.sql: self.cur.execute(s) self.conn.commit() except:#可以捕获所有异常(django事务如果中间出现程序异常终止无法回滚) try:#回滚本身也是sql执行,也有可能失败 importtraceback traceback.print_exc() print'rollback' self.conn.rollback() except: printu'回滚失败' finally: self.cur.close() self.conn.close()
更细粒度的回滚:
#在事务块中@atomic()或者withatomic(): sid=transaction.savepoint('tbkt_pxb') try: #do.......... except: transaction.savepoint_rollback(sid,'tbkt_pxb')
注意:如果有多个数据库有路由,则需要指定和路由返回一致的useing:math2下的model需要事务,即使ziyuan_new和default是同一个库,也必须使用useing=ziyuan_new
ziyuan_app=['math2','ziyuan'] ifmodel._meta.app_labelinziyuan_app: return"ziyuan_new" return'default'
调用时候必须.()方法调用
atomic块中必须注意try的使用,如果手动捕获了程序错误会导致atomic包装器捕获不到异常,也就不会回滚。要么try内代码不影响事务操作,要么就捕获异常后raise出,让atomic可以正常回滚(就是因为没有注意到这个问题,导致尝试了好几天都没成功,切记)
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!