django事务操作
1. 开启事务
1.1 开启全局事务管理
settings.py文件中加入此行配置,表示所有访问视图函数都要开始事务
ATOMIC_REQUESTS=True
1.2 装饰器
单独视图函数开启事务
# 在需要执行事务操作的函数上加装饰器表示开始事务
@transaction.atomic
def test_views(request):
1.3 with语句
局部代码块开启事务
def test_views(request):
with transaction.atomic():
#仅with包裹的下面的语句会在事务中执行
2. Django事务注意事项
2.1 不要在 atomic 块中捕获异常
2.1 报错信息
django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
[09/Nov/2023 16:03:18,118] - Broken pipe from ('127.0.0.1', 62678)
2.2 报错代码段
with transaction.atomic():
sid = transaction.savepoint()
try:
# ...数据库操作
except Exception as e:
error1 = e
transaction.savepoint_rollback(sid)
transaction.savepoint_commit(sid)
2.3 报错原因
要避免在 atomic 内部捕捉异常!
当存在 atomic 块时, Django 查看它是否正常退出或存在异常来决定是提交还是正常回滚。如果你在 atomic 内部捕捉并且处理异常,你可以对 Django 隐藏问题代码。这会导致一些意外的行为。
这主要是 DatabaseError 和它的子类的一个问题(比如 IntegrityError )。出现这样的错误之后,事务会奔溃,并且 Django 将在 atomic 块的末尾执行回滚。如果你打算在回滚发生的时候运行数据库查询,Django 将引发 TransactionManagementError 错误。当 ORM 相关的信号处理程序引发异常时,你也可能遇到这个问题。
捕捉数据库错误的正确的方法是像上方所示那样围绕 atomic 块。如有需要,为此目的可以添加额外的 atomic 块。这个模式有别的优势:如果异常发生,它会明确界定哪些操作将回滚。
如果捕获由原始SQL查询引发的异常,那么Django的行为是未指定的,并且依赖于数据库。
2.4 修改方案
try:
with transaction.atomic():
sid = transaction.savepoint()
# 采集器分配表
CollectorAllocation.objects.filter(collector_id=delete_collector_selected).update(
customer=None,
)
# 采集器分配记录添加一条记录
customers_company_name = client_customers.objects.filter(
id=delete_customer_selected).first().name_str
describe = f"由{request.user.username}从{customers_company_name}回收," \
f"快递单号:<{delete_tracking_number_input}>,退回原因:<{delete_reason_input}>"
# 修改采集器状态
client_collector.objects.filter(id=delete_collector_selected).update(is_allocation=False)
client_collector_record.objects.create(client_collector_id=delete_collector_selected,
allocation_type=2,
describe=describe)
except Exception as e:
error1 = e
transaction.savepoint_rollback(sid)
transaction.savepoint_commit(sid)
2.5 官方文档对此错误的详解
https://docs.djangoproject.com/zh-hans/3.2/topics/db/transactions/
3. Django事务回滚或提交
3.1 判断是否回滚
def save_user_product(request):
try:
from django.db import transaction
with transaction.atomic():
# ...数据库代码
except transaction.TransactionManagementError:
if transaction.get_rollback():
transaction.rollback()
logger.error("产品与用户关系保存数据库错误")
else:
print("不需要回滚")
except Exception as e:
logger.error("产品与用户关系保存数据库错误")
3.2 回滚保存点
必须配置装饰器使用
@transaction.atomic
def save_user_product(request):
sid1 = transaction.savepoint()
try:
# ......省略代码........数据库操作1
sid2 = transaction.savepoint()
# ......省略代码........数据库操作2
sid3 = transaction.savepoint()
except Exception as e:
transaction.savepoint_rollback(sid1) # 发生错误时,事务会回滚到sid1的位置
transaction.savepoint_rollback(sid2) # 发生错误时,事务会回滚到sid2的位置,数据库操作1会被提交
transaction.savepoint_rollback(sid3) # 发生错误时,事务会回滚到sid2的位置,数据库操作2会被提交
logger.error("产品与用户关系保存数据库错误")
4. Django事务异常捕获
def post(self, request):
try:
# with 语句会自动提交和回滚
with transaction.atomic():
# ...数据库操作
except Exception as e:
logger.error("产品与用户关系保存数据库错误")
python防脱发技巧

浙公网安备 33010602011771号