2011-02-04 109 views
0

我閱讀了關於事務的文檔,但仍然有點失落,應該怎麼做。 可以說我有類書籍(名稱,內容,left_key,right_key,級別)在models.py中使用方法,它將書籍內容存儲爲嵌套集合。我想使用的主要方法是Django models.py事務回滾/提交問題

@transaction.commit_on_success 
def add_node(self,right,level): 
    cursor = connection.cursor() 
    cursor.execute("UPDATE cms_Book SET left_key = left_key + 2, right_key = right_key + 2 WHERE left_key > %s",[right]) 
    cursor.execute("UPDATE cms_Book SET right_key = right_key + 2 WHERE right_key >= %s AND left_key < %s ",[right,right]) 
    cursor.execute("INSERT INTO cms_Book SET left_key = %s, right_key = %s + 1, level = %s + 1, content='roar'",[right,right,level]) 

但作爲插入主要依賴於從模板作爲參數傳遞鍵我需要檢查,如果正確的鑰匙插入。即使例如被插錯鍵,節點仍然會增加沒有什麼會中斷,也不會發生異常,但是邏輯會被打破,這不是很好,以防我需要獲得特定的節點,而不是所有的節點。

所以我有其他幾種方法來檢查邏輯是否正確。這裏是其中的一個:

def check_count(self): 
    q = Book.objects.aggregate(min_key = Min('left_key'),max_key= Max('right_key'),count_all = Count('id')) 
    return q 

我需要的是一種執行在add_node方法的所有動作是什麼,然後檢查邏輯沒有與檢查方法打破,如果沒有,一切承諾,否則回滾。我什麼樣的不明白的是,如果我使用try except塊我需要DB產生某種錯誤/異常的也不會,或例如做其中:

if (check_my_table_for_all_different_keys == none): 
      transactions.commit 
    else: 
      transactions.rollback 

check_my_table_for_all_different_keys - 如果所有密鑰都是唯一的,則不返回任何內容,否則返回相同或具有相同密鑰的對象的ID。另外我不確定應該如何確切應該看看我在哪裏提交所有3個交易,以防if-else結構的邏輯是正確的,我認爲這不是。

回答

2

關於transaction management的django文檔顯示了兩種可能的方式。這些示例假定您有一個valid函數(例如,您的check_my_table_for_all_different_keys)驗證數據庫的當前狀態,並在數據錯誤時返回false。

使用commit_on_success(如你目前做)

這樣一次函數成功返回掛起的事務被提交。當引發異常時,它會回滾。

@transaction.commit_on_success 
def add_node(self, right, level): 
    # insert/update entries 
    if not valid(): 
     raise Exception('invalid state') 

調用代碼需要處理此異常,但知道節點是否已成功添加。

使用commit_manually

這是更爲明確,因爲你必須在適當的時候提交或回滾的方式。你的例子已經準備好了。

@transaction.commit_manually 
def add_node(self, right, level): 
    # insert/update entries 
    if valid(): 
     transaction.commit() 
    else: 
     transaction.rollback() 

沒有例外,'錯誤'被壓制。如果一切正確,交易已被提交,否則將被回滾。

+0

問題2)當我試圖使用`@ transaction.commit_on_success`沒有得到保存到數據庫 問題3)將器transaction.commit()保存所有三個查詢一次?因爲我使用`transaction.commit_unless_managed()`來執行每個查詢以保存到數據庫。 問題4)如何正確地添加代碼到註釋:D,因爲`代碼`只能用於一行,據我瞭解。 – Viktor 2011-02-04 11:46:25

0

現在一切正常。我想我應該提供一個完整的代碼,如果有人會像我一樣愚蠢,並陷入=)。 因此,我們在模型中有一個類Book(名稱,內容,left_key,right_key,級別)。PY與方法:

check_difference返回false如果所有鑰匙都是獨一無二的,因爲它包含相同的密鑰所有對被取出並放入q變量否則返回true。所以,如果有什麼返回LEN(Q)> 0

def check_difference(self): 
    cursor = connection.cursor() 
    cursor.execute("SELECT t1.id, COUNT(t1.id) AS rep, MAX(t3.right_key) AS max_right \ 
        FROM cms_Book AS t1, cms_Book AS t2, cms_Book AS t3\ 
        WHERE t1.left_key <> t2.left_key \ 
        AND t1.left_key <> t2.right_key \ 
        AND t1.right_key <> t2.left_key \ 
        AND t1.right_key <> t2.right_key \ 
        GROUP BY t1.id \ 
        HAVING max_right <> SQRT(4 * rep + 1) + 1 ") 
    q = cursor.fetchall() 
    if len(q) > 0: 
     return True 
    else: 
     return False 

在這裏,我執行3個查詢,檢查表的正確性,如果一切正常,所有鍵都是唯一的,check_difference返回false那麼我們提交所有查詢並保存到數據庫,否則回滾。

@transaction.commit_manually 
def add_node(self,right,level): 
    cursor = connection.cursor() 
    cursor.execute("UPDATE cms_Book SET left_key = left_key + 2, right_key = right_key + 2 WHERE left_key > %s",[right]) 

    cursor.execute("UPDATE cms_Book SET right_key = right_key + 2 WHERE right_key >= %s AND left_key < %s ",[right,right]) 

    cursor.execute("INSERT INTO cms_Book SET left_key = %s, right_key = %s + 1, level = %s + 1, content='roar'",[right,right,level]) 
    check = self.check_difference() 
    if check == True: 
     transaction.rollback() 
    else: 
     transaction.commit() 
3

Django的1.9 +

Django提供一個單一的API來控制數據庫事務。

原子(使用=無,保存點=真)[來源]¶ 原子性是數據庫事務的定義屬性。原子允許我們創建一個代碼塊,在該代碼塊中保證數據庫的原子性。如果代碼塊成功完成,則更改將提交給數據庫。如果有異常,則更改將回滾。

原子塊可以嵌套。在這種情況下,如果內部塊成功完成,如果稍後在外部塊中引發異常,則其效果仍可以回滾。

原子可用既可作爲裝飾:

from django.db import transaction 

@transaction.atomic 
def viewfunc(request): 
    # This code executes inside a transaction. 
    do_stuff()