2011-02-04 106 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()