Django MySQL 事务机制与回滚行为的使用说明
Django 中 transaction.atomic() 的事务行为进行系统性总结,重点说明:哪些异常会触发自动回滚、哪些情况不会、为何产生差异,以及如何正确编写可控的事务逻辑。
1. transaction.atomic() 的基本行为
transaction.atomic() 会在进入时创建一个 数据库保存点(savepoint)。
代码块退出时根据执行结果决定回滚或提交:
- 若出现 未捕获的异常:自动回滚到保存点,并继续抛出该异常。
- 若代码执行正常结束:提交保存点。
核心原则:是否回滚取决于是否有异常向外抛出。
2. 会触发自动回滚的情况
2.1 未捕获的 Python 异常
只要异常没有在 atomic 块内被捕获,都会触发回滚,包括:
- ZeroDivisionError
- ValueError
- TypeError
- KeyError
- IndexError
- AssertionError
- 自定义异常
raise Exception("...")
示例:
with transaction.atomic():
obj = Model.objects.create(...)
raise Exception("abort transaction") # 未捕获 → 自动回滚
2.2 未捕获的 Django ORM / 数据库异常
数据库相关异常未被捕获时,也会触发自动回滚,包括:
- IntegrityError(唯一约束、外键约束)
- DataError(无效数据)
- OperationalError(死锁、锁超时)
- ProgrammingError(SQL 错误)
- DatabaseError
- InterfaceError
示例:
with transaction.atomic():
Model.objects.create(id=1)
Model.objects.create(id=1) # IntegrityError → 自动回滚
2.3 DRF 验证错误(raise_exception=True)
serializer.is_valid(raise_exception=True)
该语句抛出的 ValidationError 未被捕获 → 自动回滚。
3. 不会自动回滚的情况
3.1 异常被捕获并吞掉
只要异常被捕获,没有继续向外抛出,Django 会视为“执行成功”,不会回滚。
with transaction.atomic():
try:
raise Exception("error")
except Exception:
pass # 异常被吞掉 → 不回滚
若需要强制回滚,必须手动调用:
transaction.set_rollback(True)
3.2 没有异常但提前 return
业务判断不属于错误,不会自动回滚。
with transaction.atomic():
if invalid:
return Response({"error": ...}) # 不回滚
3.3 DRF 验证错误未 raise
serializer.is_valid(raise_exception=False)
if serializer.errors:
return Response(serializer.errors) # 不回滚
只有抛出异常才会回滚。
3.4 数据库层无异常但逻辑错误
例如外键检查关闭、不符合约束但 MySQL 未抛错,此类不会产生自动回滚。
3.5 使用 atomic(savepoint=False) 并在内部捕获异常
with transaction.atomic(savepoint=False):
try:
raise Exception()
except:
pass
内部异常被捕获 → 无异常向上抛出 → 不会回滚。
4. raise Exception(‘xxx’) 是否回滚?
答案:会回滚,只要未被捕获。
raise Exception('xxx') 会触发 Python 异常,atomic 在退出时检测到异常 → 自动回滚保存点。
示例:
with transaction.atomic():
raise Exception("abort") # 自动回滚
若被捕获,则不会回滚:
with transaction.atomic():
try:
raise Exception("abort")
except Exception:
pass # 无异常向上抛出 → 不回滚
5. 总结:事务回滚的唯一决定因素
Django 中事务是否回滚,唯一决定因素:
是否有异常从 atomic 块中冒出。
可以总结为:
- 未捕获异常 → 自动回滚
- 捕获异常 → 不自动回滚
- 没有异常 → 正常提交
- DRF raise_exception=True → 会回滚
- return 并非错误 → 不回滚
6. 推荐的事务编写模式(最佳实践)
from django.db import transaction
def perform_action():
try:
with transaction.atomic():
# 业务逻辑
do_something()
except Exception as e:
# atomic 已自动回滚
handle_error(e)
raise
如果希望在捕获异常后仍然回滚:
with transaction.atomic():
try:
do_something()
except Exception:
transaction.set_rollback(True) # 手动回滚
raise
到此这篇关于Django MySQL 事务机制与回滚行为的使用说明的文章就介绍到这了,更多相关Django MySQL 事务机制与回滚行为内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
解决webdriver.Chrome()报错:Message:''chromedriver'' executable n
这篇文章主要介绍了解决webdriver.Chrome()报错:Message:'chromedriver' executable needs to be in Path ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2019-06-06
Python打包模块wheel的使用方法与将python包发布到PyPI的方法详解
这篇文章主要介绍了Python打包模块wheel的使用方法与将python包发布到PyPI的方法详解,需要的朋友可以参考下2020-02-02
vscode 与pycharm 配置 autopep8自动格式化代码
autopep8是一个可以将Python代码自动排版为PEP8风格第三方包,使用它可以轻松地排版出格式优美整齐的代码,这里就为大家分享一下具体的方法2023-09-09


最新评论