Django MySQL 事務(wù)機(jī)制與回滾行為的使用說明
Django 中 transaction.atomic() 的事務(wù)行為進(jìn)行系統(tǒng)性總結(jié),重點(diǎn)說明:哪些異常會(huì)觸發(fā)自動(dòng)回滾、哪些情況不會(huì)、為何產(chǎn)生差異,以及如何正確編寫可控的事務(wù)邏輯。
1. transaction.atomic() 的基本行為
transaction.atomic() 會(huì)在進(jìn)入時(shí)創(chuàng)建一個(gè) 數(shù)據(jù)庫保存點(diǎn)(savepoint)。
代碼塊退出時(shí)根據(jù)執(zhí)行結(jié)果決定回滾或提交:
- 若出現(xiàn) 未捕獲的異常:自動(dòng)回滾到保存點(diǎn),并繼續(xù)拋出該異常。
- 若代碼執(zhí)行正常結(jié)束:提交保存點(diǎn)。
核心原則:是否回滾取決于是否有異常向外拋出。
2. 會(huì)觸發(fā)自動(dòng)回滾的情況
2.1 未捕獲的 Python 異常
只要異常沒有在 atomic 塊內(nèi)被捕獲,都會(huì)觸發(fā)回滾,包括:
- ZeroDivisionError
- ValueError
- TypeError
- KeyError
- IndexError
- AssertionError
- 自定義異常
raise Exception("...")
示例:
with transaction.atomic():
obj = Model.objects.create(...)
raise Exception("abort transaction") # 未捕獲 → 自動(dòng)回滾
2.2 未捕獲的 Django ORM / 數(shù)據(jù)庫異常
數(shù)據(jù)庫相關(guān)異常未被捕獲時(shí),也會(huì)觸發(fā)自動(dòng)回滾,包括:
- IntegrityError(唯一約束、外鍵約束)
- DataError(無效數(shù)據(jù))
- OperationalError(死鎖、鎖超時(shí))
- ProgrammingError(SQL 錯(cuò)誤)
- DatabaseError
- InterfaceError
示例:
with transaction.atomic():
Model.objects.create(id=1)
Model.objects.create(id=1) # IntegrityError → 自動(dòng)回滾
2.3 DRF 驗(yàn)證錯(cuò)誤(raise_exception=True)
serializer.is_valid(raise_exception=True)
該語句拋出的 ValidationError 未被捕獲 → 自動(dòng)回滾。
3. 不會(huì)自動(dòng)回滾的情況
3.1 異常被捕獲并吞掉
只要異常被捕獲,沒有繼續(xù)向外拋出,Django 會(huì)視為“執(zhí)行成功”,不會(huì)回滾。
with transaction.atomic():
try:
raise Exception("error")
except Exception:
pass # 異常被吞掉 → 不回滾
若需要強(qiáng)制回滾,必須手動(dòng)調(diào)用:
transaction.set_rollback(True)
3.2 沒有異常但提前 return
業(yè)務(wù)判斷不屬于錯(cuò)誤,不會(huì)自動(dòng)回滾。
with transaction.atomic():
if invalid:
return Response({"error": ...}) # 不回滾
3.3 DRF 驗(yàn)證錯(cuò)誤未 raise
serializer.is_valid(raise_exception=False)
if serializer.errors:
return Response(serializer.errors) # 不回滾
只有拋出異常才會(huì)回滾。
3.4 數(shù)據(jù)庫層無異常但邏輯錯(cuò)誤
例如外鍵檢查關(guān)閉、不符合約束但 MySQL 未拋錯(cuò),此類不會(huì)產(chǎn)生自動(dòng)回滾。
3.5 使用 atomic(savepoint=False) 并在內(nèi)部捕獲異常
with transaction.atomic(savepoint=False):
try:
raise Exception()
except:
pass
內(nèi)部異常被捕獲 → 無異常向上拋出 → 不會(huì)回滾。
4. raise Exception(‘xxx’) 是否回滾?
答案:會(huì)回滾,只要未被捕獲。
raise Exception('xxx') 會(huì)觸發(fā) Python 異常,atomic 在退出時(shí)檢測到異常 → 自動(dòng)回滾保存點(diǎn)。
示例:
with transaction.atomic():
raise Exception("abort") # 自動(dòng)回滾
若被捕獲,則不會(huì)回滾:
with transaction.atomic():
try:
raise Exception("abort")
except Exception:
pass # 無異常向上拋出 → 不回滾
5. 總結(jié):事務(wù)回滾的唯一決定因素
Django 中事務(wù)是否回滾,唯一決定因素:
是否有異常從 atomic 塊中冒出。
可以總結(jié)為:
- 未捕獲異常 → 自動(dòng)回滾
- 捕獲異常 → 不自動(dòng)回滾
- 沒有異常 → 正常提交
- DRF raise_exception=True → 會(huì)回滾
- return 并非錯(cuò)誤 → 不回滾
6. 推薦的事務(wù)編寫模式(最佳實(shí)踐)
from django.db import transaction
def perform_action():
try:
with transaction.atomic():
# 業(yè)務(wù)邏輯
do_something()
except Exception as e:
# atomic 已自動(dòng)回滾
handle_error(e)
raise
如果希望在捕獲異常后仍然回滾:
with transaction.atomic():
try:
do_something()
except Exception:
transaction.set_rollback(True) # 手動(dòng)回滾
raise
到此這篇關(guān)于Django MySQL 事務(wù)機(jī)制與回滾行為的使用說明的文章就介紹到這了,更多相關(guān)Django MySQL 事務(wù)機(jī)制與回滾行為內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python PyAutoGUI超詳細(xì)實(shí)戰(zhàn)教程 附完整教學(xué)代碼
本文將從環(huán)境搭建、基礎(chǔ)配置、鼠標(biāo)自動(dòng)化、鍵盤自動(dòng)化、屏幕操作、高級(jí)功能、實(shí)戰(zhàn)案例七個(gè)維度展開,搭配可直接運(yùn)行的教學(xué)代碼,覆蓋新手入門到實(shí)戰(zhàn)應(yīng)用的全部核心知識(shí)點(diǎn),對Python PyAutoGUI 相關(guān)知識(shí)感興趣的朋友跟隨小編一起看看吧2026-02-02
Python數(shù)據(jù)分析之獲取雙色球歷史信息的方法示例
這篇文章主要介紹了Python數(shù)據(jù)分析之獲取雙色球歷史信息的方法,涉及Python網(wǎng)頁抓取、正則匹配、文件讀寫及數(shù)值運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2018-02-02
解決python logging遇到的坑 日志重復(fù)打印問題
這篇文章主要介紹了解決python logging遇到的坑 日志重復(fù)打印問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03
探索Python函數(shù)調(diào)用為何加速代碼執(zhí)行原理
Python 作為一種解釋型語言,其執(zhí)行速度相對于編譯型語言可能會(huì)較慢,然而,在Python中,通常觀察到代碼在函數(shù)中運(yùn)行得更快的現(xiàn)象,這個(gè)現(xiàn)象主要是由于函數(shù)調(diào)用的內(nèi)部優(yōu)化和解釋器的工作方式導(dǎo)致的,本文將深入探討這個(gè)現(xiàn)象,并通過詳細(xì)的示例代碼進(jìn)行解釋2024-01-01
Python發(fā)起請求提示UnicodeEncodeError錯(cuò)誤代碼解決方法
這篇文章主要介紹了Python發(fā)起請求提示UnicodeEncodeError錯(cuò)誤代碼解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
使用Matplotlib繪制不同顏色的帶箭頭的線實(shí)例
這篇文章主要介紹了使用Matplotlib繪制不同顏色的帶箭頭的線實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
python-django中的APPEND_SLASH實(shí)現(xiàn)方法
這篇文章主要介紹了python-django中的APPEND_SLASH實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-06-06

