我阅读了有关交易的文档,但仍然有点迷失我应该如何做到这一点。 假设我在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结构的逻辑是正确的,我认为不是。
答案 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()