Django資料庫--事務及事務回滾
資料庫的讀寫操作中,事務在保證資料的安全性和一致性方面起著關鍵的作用,而回滾正是這裡面的核心操作。Django的ORM在事務方面也提供了不少的API。有事務出錯的整體回滾操作,也有基於儲存點的部分回滾。本文將討論Django中的這兩種機制的執行原理。
Django利用django.db.transaction模組中的API對資料庫進行事務的管理
Django provides a straightforward API in the django.db.transaction module to manage the autocommit state of each database connection.
主要函式:
1. get_autocommit(using=None)
判斷事務是否自動提交
2. set_autocommit(autocommit, using=None)
設定自動提交事務
這些函式使接受一個 using 引數表示所要操作的資料庫。如果未提供,則 Django 使用 "default" 資料庫。
3. on_commit(do something)
事務提交後馬上執行任務,例如celery任務
例如:
with transation.atomic:
#do something and commit the transaction
transaction.on_commit(lambda: some_celery_task.delay('arg1'))
怎麼使用?在哪裡使用?
事務是一系列的資料庫操作,在資料的安全性和減少網路請求方面都有很大的優勢。關於資料庫事務的文章有很多,我這裡就不展開討論了。
那麼ORM中有哪些相關的API呢?
trasation模組中最重要的是一個Atomic類,Atomic是一個上下文管理器。可以使用@transaction.atomic 或者with transaction.atomic 的方式來呼叫。
為了設定儲存點,即斷點進行事務的執行和回滾,可以巢狀使用with transaction.atomic,例如官網的例子(虛擬碼):
with transaction.atomic(): # Outer atomic, start a new transaction
transaction.on_commit(foo) #事務提交後馬上執行foo函式
try:
with transaction.atomic(): # Inner atomic block, create a savepoint
transaction.on_commit(bar) #事務提交後馬上執行foo函式
raise SomeError() # Raising an exception - abort the savepoint
except SomeError:
rollback
雖然錯誤raiseSomeError是從‘內部’的儲存點發出來的,但只會影響到‘外部’的儲存點,即只會回滾前面的資料庫操作。
下面還會討論另一種建立儲存點的方法。
在使用transaction.atomic前需要注意的問題:
1. 資料庫的自動提交預設為開啟,如果要將它關閉,必須很小心。一旦使用了transaction,即關閉了自動提交。
2. 如果資料庫之前的使用的是自動提交,那麼在切換為非自動提交之前,必須確保當前沒有活動的事務,通常可以執行commit() 或者 rollback() 函式來把未提交的事務提交或者回滾。
一、整體回滾
所有的資料庫更新操作都會在一個事務中執行,如果事務中任何一個環節出現錯誤,都會回滾整個事務。
案例(虛擬碼):
from django.db import transaction
# open a transaction
@transaction.atomic
def func_views(request):
do_something()
do_something_more()
try:
transaction.commit()
except Exception:
transaction.rollback()
二、儲存點Savepoint(斷點回滾)
儲存點是事務中的標記,從原理實現上來說是一個類似儲存結構的類。可以回滾部分事務,而不是完整事務,同時會儲存部分事務。python後端程式可以使用儲存點。
一旦開啟事務atomic(),就會構建一系列等待提交或回滾的資料庫操作。通常,如果發出回滾命令,則會回滾整個事務。儲存點則提供了執行細粒度回滾的功能,而不是將執行的完全回滾transaction.rollback()。
工作原理:savepoint通過對返回sid後面的將要執行的資料庫操作進行計數,並儲存在內建的列表中,當對資料庫資料庫進行操作時遇到錯誤而中斷,根據sid尋找之前的儲存點並回滾資料,並將這個操作從列表中刪除。
相關API:
1. savepoint(using = None)
建立一個新的儲存點。這表示處於正常狀態的事務的一個點。返回儲存點ID(sid)。在一個事務中可以建立多個儲存點。
2. savepoint_commit(sid,using = None)
釋出儲存點sid,從建立儲存點開始執行的資料庫操作將成為可能回滾事務的一部分
3. savepoint_rollback(sid,using = None)
將事務回滾到儲存點sid
4. clean_savepoints(using = None)
重置用於生成唯一儲存點ID的計數器
值得注意的是:
這些函式中的每一個都接受一個using引數,該引數是資料庫的名稱。如果using未提供引數,則使用"default"預設資料庫。
案例:
from django.db import transaction
# open a transaction
@transaction.atomic
def add_author_views(request):
# 自動提交方式
# Author.objects.create(name=u'wangbaoqiang',age=33,email='[email protected]')
author_name = u'linghuchong'
author = Author(name=author_name,age=26,email='[email protected]')
author.save()
# transaction now contains author.save()
sid = transaction.savepoint()
try:
count = Count(name=author_name, article_amount=1)
count.save()
# transaction now contains author.save() and count.save()
transaction.savepoint_commit(sid)
# open transaction still contains author.save() and count.save()
except IntegrityError:
transaction.savepoint_rollback(sid)
# open transaction now contains only count.save()
# 儲存author操作回滾後,事務只剩下一個操作
transaction.clean_savepoints() #清除儲存點
注意:希望當遇到錯誤得到回滾的事務一定要放在try裡面(如果放在try外面,雖然不會報錯,但是是不會執行的)。如上面的例子,如果在給Count表執行插入資料發生錯誤,就會‘斷點’回滾到Count表插入資料前,Author表插入的資料不變。
結果顯示:
Author表
Count表