2017-08-11 45 views
1

首先,this GitHub project包含我在本文中討論和詢問的代碼。這是一個非專有和簡短的例子,我的團隊正在處理這些事情。在Django出現異常時回滾一組數據庫事務

我正在研究一個項目,我們使用Django數據庫事務在表格上進行更新,以準備轉換爲可用於業務目的的XML。我們通過使用transaction.atomic()上下文管理器來確定錯誤得到正確處理,從而修復了以前破壞的代碼。每個UPDATE語句都位於一個上下文管理器中,而上下文管理器又位於一個函數中。有三個在程序中調用另一個函數(bulk_set())內的這些功能(set_yes()set_no()broken_query()):

models.py

from __future__ import unicode_literals 
from django.db import connection, DatabaseError, transaction 
import pandas as pd 

from django.db import models 


class TestTable(models.Model): 
    value1 = models.IntegerField() 
    value2 = models.IntegerField() 
    same = models.CharField(max_length=3, null=True) 


def setup_table(): 
    """ 
    sets up the basic table. 
    several rows will have matching values, some won't. 
    :return: None 
    """ 
    row1 = TestTable(value1=1, value2=1) 
    row1.save() 

    row2 = TestTable(value1=2, value2=1) 
    row2.save() 

    row3 = TestTable(value1=56, value2=1) 
    row3.save() 

    row4 = TestTable(value1=10, value2=10) 
    row4.save() 


def set_yes(): 
    """ 
    sets "same" column on rows with matching value1 and value2 columns to "yes" 
    :return: None 
    """ 
    query = ''' 
     UPDATE db_app_testtable 
     SET same = 'yes' 
     WHERE value1 = value2 
    ''' 
    try: 
     with transaction.atomic(): 
      cursor = connection.cursor() 
      cursor.execute(query) 
    except DatabaseError as ex: 
     print "set_yes has error %s" % (ex) 
     raise 
    finally: 
     cursor.close() 
     print_table() 


def set_no(): 
    """ 
    sets "same" column on rows with differing value1 and value2 columns to "no" 
    :return: None 
    """ 
    query = ''' 
     UPDATE db_app_testtable 
     SET same = 'no' 
     WHERE value1 != value2 
    ''' 
    try: 
     with transaction.atomic(): 
      cursor = connection.cursor() 
      cursor.execute(query) 
    except DatabaseError as ex: 
     print "set_no has error %s" % (ex) 
     raise 
    finally: 
     cursor.close() 
     print_table() 


def broken_query(): 
    """ 
    a function meant to break. there is no column named 'different', so this should cause 
    a DatabaseError to be thrown upon execution. 
    :return: None 
    """ 
    query = ''' 
     UPDATE db_app_testtable 
     SET different = 'lol no' 
     WHERE value1 = value2 
    ''' 
    try: 
     with transaction.atomic(): 
      cursor = connection.cursor() 
      cursor.execute(query) 
    except DatabaseError as ex: 
     print "broken_query has error %s" % (ex) 
     raise 
    finally: 
     cursor.close() 
... 

def bulk_set(): 
    try: 
     set_no() 
     set_yes() 
     broken_query() 
    except Exception as gen_ex: 
     print "Exception has occurred." 
     raise 

正如你所看到的,broken_query()將無法​​正常工作,這是通過設計。我們試圖設計一個代碼塊,如果broken_query()失敗,它將回滾set_yes()set_no()完成的操作,這是不可避免的。

鑑於django.db.transaction.atomic()的功能,這可能嗎?讀取documentation時,它說:「如果代碼塊已成功完成,則更改將提交給數據庫。如果發生異常,則更改將回滾。」「我的問題是,這可以擴展到使在同一代碼塊中調用的其他操作也會回滾?

回答

0

是的,在with atomic.transaction的同一個塊中,如果您撥打raise Exception,您將使事務回滾。

+0

瞭解,但原子性只能擴展到該事務。我想以某種方式使事務表現爲一個集合,以便如果一個失敗,它們全部失敗並且全部回滾。 – nerdenator

+0

所以你需要將所有的事務都放在原子塊中。 – wololoooo

+0

雖然我認爲這不是建議,但它的工作原理。 – wololoooo

相關問題