数据库操作的事务与锁
django
后端逻辑
def transaction_add(request, pk):
res_code = ResCode()
if request.method == 'POST':
form = TransactionForm(data=request.POST)
if not form.is_valid():
res_code.detail = form.errors
return JsonResponse(res_code.dict)
amount = form.cleaned_data.get('amount')
status = form.cleaned_data.get('status')
# 防止页面错误
try:
# 原子性操作,事务绑定,失败一起回滚
from django.db import transaction
with transaction.atomic():
#select_for_update()加锁,只能单个事务执行
trader = models.User.objects.filter(pk=pk).select_for_update().first()
form.instance.trader = trader
form.instance.operator_id = request.user_info.uid
if status == 1:
trader.balance += amount
elif status == 2:
if trader.balance < amount:
# 自定义显示错误,amount为字段名
res_code.detail = {
'amount': [f'余额不足,当前余额为{trader.balance}']
}
return JsonResponse(res_code.dict)
trader.balance -= amount
trader.save()
form.save()
except Exception as e:
res_code.detail = {
'amount': ['操作失败', e]
}
return JsonResponse(res_code.dict)
res_code.success = True
res_code.detail = ''
return JsonResponse(res_code.dict)
drf
局部事务(*)
基于上下文管理,如果出现异常则自动回滚;无异常则自动提交。
from rest_framework.views import APIView
from rest_framework.response import Response
from django.db import transaction
from api import models
class Demo1View(APIView):
def get(self, request, *args, **kwargs):
try:
with transaction.atomic():
models.UserInfo.objects.create(name='v1', age=1)
models.Order.objects.create(name='v1', age=1)
except Exception as e:
print("异常,自动回滚")
return Response("...")
事务提交的回调函数(本质上就是事务完成后,自动执行一个函数)
from rest_framework.views import APIView
from rest_framework.response import Response
from django.db import transaction
from api import models
from functools import partial
def db_success_callback(*args, **kwargs):
print(args, **kwargs)
class Demo1View(APIView):
def get(self, request, *args, **kwargs):
try:
with transaction.atomic():
# 回调函数,事务正常提交自动执行
transaction.on_commit(db_success_callback)
transaction.on_commit( partial(db_success_callback, 11, 22, 33) )
models.UserInfo.objects.create(name='v1', age=1)
models.Order.objects.create(title='v1', count=1)
except Exception as e:
print("异常,自动回滚") # on_commit回调函数内部异常时不会回滚
return Response("...")
回滚到 指定事务点
from rest_framework.views import APIView
from rest_framework.response import Response
from django.db import transaction
from api import models
class Demo1View(APIView):
def get(self, request, *args, **kwargs):
try:
with transaction.atomic():
# 回调函数,事务正常提交自动执行
n1 = transaction.savepoint()
models.UserInfo.objects.create(name='v1', age=1)
n2 = transaction.savepoint()
models.UserInfo.objects.create(name='v2', age=1)
# 必须在事务里面,回顾到指定 事务点,后续东西不提交
transaction.savepoint_rollback(n2)
except Exception as e:
print("异常,自动回滚", e) # on_commit回调函数内部异常时不会回滚
return Response("...")
视图事务
针对整个视图进行开启事务:
- 视图内,有数据库操作异常,自动回滚
- 视图内,有其他异常,不会回滚。
from rest_framework.views import APIView
from rest_framework.response import Response
from django.db import transaction, IntegrityError
from api import models
class Demo1View(APIView):
@transaction.atomic
def get(self, request, *args, **kwargs):
try:
models.UserInfo.objects.create(name='v100', age=1)
models.UserInfo.objects.create(name="v200", age="xxx") # 有异常,回滚,即:v100不会保存
int("asdf") # 有异常,不会滚,即:两条数据正常保存到数据库
except Exception as e:
pass
return Response("...")
定义事务点,自定义回滚位置
from rest_framework.views import APIView
from rest_framework.response import Response
from django.db import transaction, IntegrityError
from api import models
class Demo1View(APIView):
@transaction.atomic
def get(self, request, *args, **kwargs):
try:
models.UserInfo.objects.create(name='v10', age=1)
n1 = transaction.savepoint()
models.UserInfo.objects.create(name="v11", age=1)
n2 = transaction.savepoint()
models.UserInfo.objects.create(name='v12', age=1)
n3 = transaction.savepoint()
models.UserInfo.objects.create(name='v13', age=1)
# 后续读取到某些值后,发现 v12不应该创建,那么就可以主动回滚
transaction.savepoint_rollback(n1)
except Exception as e:
print("有异常", e)
return Response("...")
有的cvb需要把装饰器放在dispatch上才生效
from django.utils.decorators import method_decorator
from django.db import transaction
@method_decorator(transaction.atomic, name='dispatch')
class LoginView(APIView):
pass
全局事务
效率低:项目中一般不会使用。
如果想要开启全局事务,需要在连接数据库时多设置一个参数
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'dbhot4',
'USER': 'root',
'PASSWORD': 'root123',
'HOST': '127.0.0.1',
'PORT': '3306',
'ATOMIC_REQUESTS': True
}
}
只要视图函数执行异常,无论是什么原因触发,均自动回滚。
class Demo1View(APIView):
def get(self, request, *args, **kwargs):
models.UserInfo.objects.create(name='v1', age=1)
models.UserInfo.objects.create(xxxxxxx='v2', age=1) # 错误
return Response("...")
class Demo1View(APIView):
def get(self, request, *args, **kwargs):
models.UserInfo.objects.create(name='v1', age=1)
models.UserInfo.objects.create(name='v2', age=1)
int("asdf") # 错误
return Response("...")
如果视图函数执行不报错(try处理异常,也叫不报错),则不会回滚
class Demo1View(APIView):
def get(self, request, *args, **kwargs):
try:
models.UserInfo.objects.create(name='v1', age=1)
models.UserInfo.objects.create(xxxxxxx='v2', age=1)
int("xxx")
except Exception as e:
pass
return Response("...")
# 视图函数执行没有报错,不会滚回。
如果开启了全局事务,想要免除某个指定的函数不需要开启事务,则可以使用
from rest_framework.views import APIView
from rest_framework.response import Response
from django.db import transaction, IntegrityError
from api import models
from django.utils.decorators import method_decorator
@method_decorator(transaction.non_atomic_requests, name='dispatch')
class Demo1View(APIView):
def get(self, request, *args, **kwargs):
models.UserInfo.objects.create(name='v100', age=1)
models.UserInfo.objects.create(name="v200", age="xxx") # 报错
return Response("...")
本文作者:Sherwin
本文链接:https://www.cnblogs.com/sherwin1995/p/16703283.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步