1.Django之数据库事务
# Django默认事务行为
Django的默认使用自动提交模式。除非事务处于活动状态,否则每个查询都会立即提交到数据库。
为了确保ORM操作的完整性,Django自动使用事务或者保存点。
TestCase由于性能原因,Django的类还会在事务中包装每个测试。
# 事务与HTTP请求
处理方式:将每个HTTP请求包装在事务中。
工作原理:在调用视图函数之前,Django启动一个事务。如果视图响应正常,Django会提交事务。如果视图产生异常,Django将回滚事务。
自定义事务:通过atomic()上下文管理器来使用视图代码中的保存点执行子事务。
结果:在视图结束时,将提交所有更改或不提交任何更改。
2.atomic:
事务控制(atomic)
atomic(using = None,savepoint = True)
using:数据库名称的参数。如果未提供此参数,Django将使用该"default" 数据库。
savepoint :是否创建保存点。
atomic允许我们创建一个保证数据库原子性的代码块,如果代码块执行正常,则更改将提交到数据库。如果存在异常,则回滚更改。
atomic可以嵌套。在这种情况下,当内部块成功完成时,如果稍后在外部块中引发异常,则仍可以回滚其效果。
# atomic 使用方式
1.作为装饰器使用
方式一:
@api_view(['POST'])
@transaction.atomic
def test(request):
obj = Scenthreadapi.objects.filter(planname="test1011", threadname="thread1012",
threads=123, modplain="size-10k")
obj.update(threadname="0000000000000")
obj.xxx #这里我直接让保存发现我的数据库没有修改
return JsonResponse('ok', safe=False
方式二:
@api_view(['POST'])
@transaction.atomic
def test(request):
try:
obj = Scenthreadapi.objects.filter(planname="test1011", threadname="thread1012",
threads=123, modplain="size-10k")
obj.update(threadname="0000000000000")
obj.xxx # 这里我是用异常捕获了,数据库发生了改变,说明默认事务是基于异常和报错的
except:
pass
return JsonResponse('ok', safe=False)
2.作为上下文管理器使用
@api_view(['POST'])
def test(request):
with transaction.atomic():
obj = Scenthreadapi.objects.filter(planname="test1011", threadname="thread1012",
threads=123, modplain="size-10k")
obj.update(threadname="0000000000000")
obj.xxx # 这里我直接让保存发现我的数据库没有修改
return JsonResponse('ok', safe=False)
@api_view(['POST'])
def test(request):
with transaction.atomic():
try:
obj = Scenthreadapi.objects.filter(planname="test1011", threadname="thread1012",
threads=123, modplain="size-10k")
obj.update(threadname="0000000000000")
obj.xxx # 这里我是用异常捕获了,数据库发生了改变,说明默认事务是基于异常和报错的
except:
pass
return JsonResponse('ok', safe=False)
总结:通过上面两个我发现加入你在处理的函数使用异常捕获,事务就不能很好的进行
3.上下文管理器嵌套使用
1.嵌套捕获异常
@api_view(['POST'])
def test(request):
with transaction.atomic():
with transaction.atomic():
obj = Scenthreadapi.objects.filter(planname="test1011", threadname="thread1012",
threads=123, modplain="size-10k")
obj.update(threadname="0000000000000")
# obj.xxx
obj.xxx # 放在这两个地方都一样,数据库都没有发生改变,所以可以知道如果外部发生异常,会将内部事务的操作仪器回退
return JsonResponse('ok', safe=False)
2.嵌套捕获异常
@api_view(['POST'])
def test(request):
with transaction.atomic():
with transaction.atomic():
try:
obj = Scenthreadapi.objects.filter(planname="test1011", threadname="thread1012",
threads=123, modplain="size-10k")
obj.update(threadname="0000000000000")
obj.xxx # 数据发生了改变
except:
pass
return JsonResponse('ok', safe=False)
--------------------------------------------------------------
@api_view(['POST'])
def test(request):
with transaction.atomic():
with transaction.atomic():
try:
obj = Scenthreadapi.objects.filter(planname="test1011", threadname="thread1012",
threads=123, modplain="size-10k")
obj.update(threadname="0000000000000")
except:
pass
obj.xxx # 数据库没有改变,被外部事务回退了
return JsonResponse('ok', safe=False)
3.异常是很常见的,但是还需回退被异常捕获的事务,手动回退 ******
@api_view(['POST'])
def test(request):
with transaction.atomic():
sid = transaction.savepoint()
try:
obj = Scenthreadapi.objects.filter(planname="test1011", threadname="thread1012",
threads=123, modplain="size-10k")
obj.update(threadname="0000000000000")
obj.xxx
except:
transaction.savepoint_rollback(sid) # 既然异常被捕获了,我直接在异常中手动回退
return JsonResponse('ok', safe=False)
# Django事务管理代码
1.进入最外面的atomic块时打开一个事务;
2.进入内部atomic块时创建保存点;
3.退出内部块时释放或回滚到保存点;
4.退出最外面的块时提交或回滚事务。
atomic(using = None,savepoint = True)
atomic接受一个using应该是数据库名称的参数。如果未提供此参数,Django将使用该"default" 数据库。
通过将savepoint参数设置为False,可以禁用为内部块创建保存点。如果发生异常,Django将在使用保存点退出第一个父块时执行回滚(如果有保存点),否则执行最外层的块。原子性仍然由外部事务保证。只有当保存点的开销显著时,才应该使用此选项。它的缺点是破坏了上面描述的错误处理。(#加入)
当自动提交被关闭时,可以使用atomic。它只会使用保存点,即使对于最外层的块也是如此。