1. 程式人生 > >Django資料庫--事務及事務回滾

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表