有些时候我们需要对数据库进行一连串的操作,如果其中某一个操作失败,那么其他的操作也要跟着回滚到操作以前的状态。
例如用户A给用户B转账,A账户减少100元,B账户增加100元,如果A账户减少了100元,B账户增加100元时却失败了,A平白无故损失了100元,这种情况是不可接受的。要么全部成功要么全部失败,不能出现部分成功、部分失败!
Django中 @transaction.atomic()装饰器可实现事务操作如下:
@transaction.atomic()
def addProject(request, **kwargs):
"""
新增项目
:param request:
:return:
"""
project_name = request.POST.get('projectName', None)
project_type = request.POST.get('projectType', None)
if project_name is None or len(project_name) < 1 or len(project_name) > 32:
return JsonResponse({"statusCode": "130001",
"message": "项目名称为空或者太长"},
status=status.HTTP_200_OK)
if project_type is None or int(project_type) < 0 or int(project_type) > 5:
return JsonResponse(
{"statusCode": "130002", "message": "无效项目类型"}, status=status.HTTP_200_OK)
uf = ProjectForm(request.POST) # 绑定POST动作
sid = transaction.savepoint()
if uf.is_valid():
# 保存项目
project = uf.save()
project = Project.objects.get(id=project.id)
userid = request.COOKIES.get("id", None)
user = User.objects.get(id=userid)
try:
# 保存用户项目关系
conn_project = Users(project=project, user=user, userType=0)
conn_project.save()
# 添加默认接口分组
groupName = "默认分组"
groupname = Group(
project=project,
groupName=groupName,
parentGroupID=0,
isChild=0)
groupname.save()
# 添加状态码默认分组
statuscodegroup = Code_Group(
project=project,
groupName=groupName,
parentGroupID=0,
isChild=0)
statuscodegroup.save()
# 添加项目文档默认分组
documentgroup = Document_Group(
project=project,
groupName=groupName,
parentGroupID=0,
isChild=0)
documentgroup.save()
# 添加定时任务默认分组
crontab_group = Crontab_Group(project=project,
groupName=groupName,
parentGroupID=0,
isChild=0)
crontab_group.save()
# 添加操作记录
save_operation_log(
0,
user,
'创建项目:' +
project_name,
project,
0,
project.id)
transaction.savepoint_commit(sid)
return JsonResponse(
{
"projectInfo": {
"projectType": project.projectType,
"projectID": project.id,
"projectUpdateTime": project.projectUpdateTime,
"projectVersion": project.projectVersion},
"statusCode": "000000"},
status=status.HTTP_200_OK)
except BaseException as e:
transaction.savepoint_rollback(sid)
logger.error('新增项目失败:' + str(e))
return JsonResponse({"status": "130000",
"messages": "新增项目失败"},
status=status.HTTP_400_BAD_REQUEST)以上代码实现新增项目操作,新增项目后创建用户关系、状态码、文档等相关操作,其中任何一个步骤发送异常所有相关表都会恢复到项目创建前状态。
还有最后一个大杀器。如果你想让所有的数据库操作都是事务,那就在 settings.py 里配置:
# settings.py
# 以 sqlite 为例
DATABASES = {
'default': {
'ENGINE': ...,
'NAME': ...,
# 加上这条
'ATOMIC_REQUESTS': True,
}
}
然后可以用 non_atomic_requests 标记不需要成为事务的视图:
@transaction.non_atomic_requests
def create_project(request):
...
另外,类视图也是可以成为事务的:
class CreateProject(View):
@transaction.atomic
def get(self, request):
...
最后总结一下,并非任意对数据库的操作序列都是事务。数据库事务拥有 ACID特性:
- 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
- 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
- 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。
官方文档:https://docs.djangoproject.com/en/3.0/topics/db/transactions/





Comments | NOTHING