事务处理(transaction)对于Web应用开发至关重要, 它可以维护数据库的完整性, 使整个系统更加安全。比如用户A通过网络转账给用户B,数据库里A账户中的钱已经扣掉,而B账户在接收过程中服务器突然发生了宕机,这时数据库里的数据就不完整了。加入事务处理机制后,如果在一连续交易过程中发生任何意外, 程序将回滚,从而保证数据的完整性。本文将总结事务的四大特性以及Django项目开发中如何操作事务。
事务的四大特性(ACID)
如果想要说明一个数据库或者一个框架支持事务性操作,则必须要满足下面的四大特性:
原子性(Atomicity):整个事务中的所有操作,要么全部完成,要么全部不完成。事务在执行过程中发生错误,会被回滚到事务开始前的状态。
一致性 (Consistency):事务开始之前和事务结束后,数据库的完整性约束没有被破坏。
隔离性(Isolation):隔离性是指当多个用户并发访问数据库时,比如同时访问一张表,数据库每一个用户开启的事务,不能被其他事务所做的操作干扰,多个并发事务之间,应当相互隔离。
持久性(Durability):事务执行成功后,该事务对数据库的更改是持久保存在数据库中的,不会被回滚。
局部开启事务
Django项目中局部开启事务,可以借助于transaction.atomic方法。使用它我们就可以创建一个具备原子性的代码块,一旦代码块正常运行完毕,所有的修改会被提交到数据库。反之,如果有异常,更改会被回滚。
# 案例一:函数视图
from django.db import transaction
@transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
# 案例二:基于类的视图
from django.db import transaction
from rest_framework.views import APIView
class OrderAPIView(APIView):
# 开启事务,当方法执行完以后,自动提交事务
@transaction.atomic
def post(self, request):
pass
使用了atomic装饰器,整个视图方法里的代码块都会包裹着一个事务中运行。有时我们希望只对视图方法里一小段代码使用事务,这时可以使用transaction.atomic()显式地开启事务,如下所示:
from django.db import transaction
def viewfunc(request):
# 默认自动提交
do_stuff()
# 显式地开启事务
with transaction.atomic():
# 下面这段代码在事务中执行
do_more_stuff()
Savepoint回滚
在事务操作中,我们还会经常显式地设置保存点(savepoint)。一旦发生异常或错误,我们使用savepoint_rollback方法让程序回滚到指定的保存点。如果没有问题,就使用savepoint_commit方法提交事务。示例代码如下:
from django.db import transaction
def viewfunc(request):
# 默认自动提交
do_stuff()
# 显式地开启事务
with transaction.atomic():
# 创建事务保存点
sid = transaction.savepoint()
try:
do_more_stuff()
except Exception as e:
# 如发生异常,回滚到指定地方。
transaction.savepoint_rollback(sid)
# 如果没有异常,显式地提交一次事务
transaction.savepoint_commit(sid)
return HttpResponse("Success")
示例代码
下面的是view试图
from rest_framework.response import Response
from testtranc.models import TestTranc as trancModel
from rest_framework.viewsets import GenericViewSet
from rest_framework.decorators import action
from testtranc.Serializers.trancSerializer import TestTrancSerialize
from django.db import transaction
from django.db import connections
from rest_framework import status
class TestTrancView(GenericViewSet):
queryset = trancModel.objects.all()
serializer_class = TestTrancSerialize
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
def create(self, request, *args, **kwargs):
try:
with transaction.atomic():
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
self.runsql()
return Response(serializer.data, status=status.HTTP_201_CREATED)
except:
return Response("失败", status=status.HTTP_404_NOT_FOUND)
def runsql(self):
with connections['default'].cursor() as cursor:
cursor.execute("insert into testtran (name,age) values('eee',100)")
model
from django.db import models
class TestTranc(models.Model):
id = models.BigAutoField(primary_key=True,verbose_name='主键')
name = models.CharField(max_length=100,blank=False,null=False,unique=True,verbose_name="姓名")
age = models.IntegerField(blank=False,null=False)
class Meta:
db_table = 'testtran'
# Create your models here.
serialize
from rest_framework.serializers import ModelSerializer
from testtranc.models import TestTranc
class TestTrancSerialize(ModelSerializer):
class Meta:
model = TestTranc
fields = '__all__'