概要
Transaction是django进行数据库原子性操作在python层面上的实现. 简单来说, 被transaction.atomic()包裹的代码块只在代码块顺利完成后进行数据库层面的commit.实际开发当中,遇到了一些问题.
1. transaction事务内不执行数据库的commit操作,除非手动commit
transaction最基本的功能。
代码场景:
在事务当前启动celery异步任务, 无法获取未提交的改动.
def example_view(request):
with transaction.atomic():
change_obj() # 修改对象变量
obj.save()
async_task.delay(obj.id)
def async_task(obj_id):
obj = Model.objects.get(pk=obj_id)
read_the_obj() # 读取对象信息
在使用transaction当中, Model.save()都不做commit,因此如果在transaction当中设置异步任务,使用get()查询数据库,将看不到对象在事务当中的改变.这也是实现”可重复读”的事务隔离级别,即同一个事务里面的多次查询都应该保持结果不变.
2.transaction只对数据库层的操作进行事务管理,不能理解为python操作的事务管理
代码如下:
def example_view(request):
tag = False
with transaction.atomic():
tag = True
change_obj() # 修改对象变量
obj.save()
raise DataError
print("tag = ",tag)
tag = True #输出内容
即使事务代码块发生了DataError,事务回滚,也仅是数据库层面的回滚,针对python的操作依然已完成.
甚至是对Model.Object进行的操作会也会存在变量当中.
如,
def example_view(request):
obj.changed = False
with transaction.atomic():
obj.changed = True
change_obj() # 修改对象其他变量
obj.save()
raise DataError
print("obj.changed = ",obj.changed)
obj.changed = True #输出内容
发生Dataerror异常的回滚仅在数据库层面操作,因此不可以根据model object的属性值判断是否正确完成了事务.
另外,虽然Django对数据库层面以ORM完成了很具体的抽象,但应该要清楚地意识到我们操作的model object和数据库内容本质不同,DJANGO只在查询和提交时进行数据库操作.