python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Django事务ATOMIC_REQUESTS

Django中的事务ATOMIC_REQUESTS

作者:蓝绿色~菠菜

这篇文章主要介绍了Django中的事务ATOMIC_REQUESTS使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

Django事务ATOMIC_REQUESTS

Django的默认事务行为

Django 的默认行为是以自动提交模式运行。

除非事务处于活动状态,否则每个查询都会立即提交到数据库。

将事务绑定到HTTP请求

在 Web 上处理事务的常用方法是将每个请求包装在事务中。

在要为其启用此行为的每个数据库的配置中设置ATOMIC_REQUESTS为True。

DATABASES = {
        'default': {
			'ENGINE': 'django.db.backends.mysql',
        	'NAME': 'testdb',
        	'USER': 'hayley',
        	'PASSWORD': '******',
        	'HOST': 'localhost',
        	'PORT': '3306',
            'ATOMIC_REQUESTS': True,
        }
    }

它是这样工作的:在调用视图函数之前,Django 会启动一个事务。如果生成的响应没有问题,则 Django 提交事务。如果视图产生异常,Django 会回滚事务。

您可以使用视图代码中的保存点执行子事务,通常使用atomic()上下文管理器。但是,在视图结束时,将提交所有更改或不提交任何更改。

虽然每个请求都开启事务比较方便,但它也会在流量增加时变得低效。为每个视图打开一个事务有一些开销。对性能的影响取决于应用程序的查询模式以及数据库处理锁定的能力。

以上是全局性的配置, 如果要对某个http请求放水(然后自定义事务),可以用non_atomic_requests修饰器

from django.db import transaction
class xxx(xxxView):
    @transaction.non_atomic_requests
    def post(self, request, *args, **kwargs):
        ...
 

或者关闭全局事务,为每个请求单独设置事务:

 
from django.db import transaction
class xxx(xxxView):
    @transaction.atomic
    def post(self, request, *args, **kwargs):
        with transaction.atomic():
            ...
 

Django中的事务介绍

Django事务介绍

在Django中,它的 默事务行为是自动提交。

除非事务正在执行,每个查询将会马上自动提交到数据库, 例如:

# ApiData为model
ApiData.objects.create(name='测试名字', path='/')
ApiData.objects.filter(id=1).update(name='测试名字', path='/')

如果没有手动设置事务,那么这两条代码在执行完成后就会马上提交到数据库中进行保存,Django 自动使用事务或还原点,以确保需多次查询的 ORM 操作的一致性,特别是 delete() 和 update() 操作。

使用Django事务

通过django手动创建事务的方式一般为两种:装饰器和 with :

装饰器:

@api_view(['POST'])
@transaction.atomic
def test_views(request):
    """
    该方法会在一个事务中执行
    """
    ApiData.objects.create(name='测试名字', path='/')
    ApiData.objects.filter(id=1).update(name='测试名字', path='/')
    return Response(data={'msg': '创建成功!'})

with语句:

@api_view(['POST'])
def test_views(request):
    try:
        with transaction.atomic(): #仅with包裹的下面的语句会在事务中执行
            ApiData.objects.create(name='测试名字', path='/')
            ApiData.objects.filter(id=1).update(name='测试名字', path='/')
    except Exception as e:
        pass
    return Response(data={'msg': '创建成功!'})

需要注意的是当事务回滚时,模型的属性需要手动恢复。

例如下面的代码, obj.active 的初始值是 False .我们设置了 obj.active=True 然后进行了保存 obj.save() 操作,但这个时候发生了异常导致保存失败了,那此时的 obj.active 的值还是为 True ,并不会因为保存失败而变为 False

from django.db import DatabaseError, transaction
obj = MyModel(active=False)
obj.active = True
try:
    with transaction.atomic():
        obj.save()
except DatabaseError:
    pass
if obj.active: #下面的代码
    ...

因此,针对上面的代码我们可以在抛异常处将 active 的值设为 False 来达到恢复模型属性的值的目的:

try:
    with transaction.atomic():
        obj.save()
except DatabaseError:
    obj.active=False #手动恢复active属性

全局事务

如果为了图省事而场景也较为通用,我们可以设置全局事务配置来让每个请求view都使用事务:

settings.py 配置文件中增加下面配置:

ATOMIC_REQUESTS=True

这样就将每个视图包裹在这个数据库的事务中了,只有视图未完成执行成功,都将回滚到请求前的初始状态。

另外也可以增加 AUTOCOMMIT=False 的配置项来禁用Django的事务管理以此来使用自定义的事务。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文