Django models.py事务回滚/提交问题

时间:2011-02-04 00:24:00

标签: django transactions models

我阅读了有关交易的文档,但仍然有点迷失我应该如何做到这一点。 假设我在models.py中有类Book(name,content,left_key,right_key,level) with methods,它将书籍内容存储为嵌套集。我想要使​​用的主要方法是

@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方法中执行所有操作,然后检查逻辑是否没有中断check方法,如果没有,则提交一切否则回滚。我有点不明白的是,如果我使用try除了块我需要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结构的逻辑是正确的,我认为不是。

3 个答案:

答案 0 :(得分:3)

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()

没有异常被提出,'错误'被静音。如果一切正确,则已提交事务,否则将回滚。

答案 1 :(得分:3)

Django 1.9 +

Django提供了一个API来控制数据库事务。

atomic(using = None,savepoint = True)[source]¶ 原子性是数据库事务的定义属性。 atomic允许我们创建一个代码块,在该代码块中保证数据库的原子性。如果代码块成功完成,则更改将提交到数据库。如果存在异常,则会回滚更改。

原子块可以嵌套。在这种情况下,当内部块成功完成时,如果稍后在外部块中引发异常,则仍然可以回滚其效果。

atomic可用作装饰器:

from django.db import transaction

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

答案 2 :(得分:0)

现在一切正常。我想我应该提供一个完整的代码,如果有人会像我一样愚蠢而陷入困境=)。   所以我们在models.py 中有一个类Book(name,content,left_key,right_key,level)和方法:

  

check_difference 如果所有键都是唯一的,则返回false,否则返回true,因为所有包含相同键的对都被提取并放入 q 变量中。因此,如果返回任何内容,则len(q)是&gt; 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()