2010-07-04 117 views
4

我已在下面的代码段重写保存的模型的方法,包括:django的回滚事务

@transaction.commit_on_success 
def save(self, *args, **kwargs): 

    try: 
     transaction.commit() 
     self.qa.vote_down_count += 1 
     self.qa.save() 

     super(self.__class__, self).save(*args, **kwargs) 

    except: 
     transaction.rollback() 
     raise 
    else: 
     transaction.commit() 

预期的行为将是:self.qa属性vote_down_count递增一,但是,如果任何在super(self)save方法中发生异常事务回滚(这意味着self.qa.vote_down_count + = 1不会在数据库中提交)。

实际的行为是:self.qa.vote_down_count + = 1被提交到数据库,即使IntegrityError异常从超级(自我)保存引发。

任何虽然?

+0

你为什么犯第一件事情,然后在结束时再次犯下? – 2010-07-04 12:49:56

+0

提交第一件事就是打开交易,确保提交之前发生的所有事情,不是吗? – 2010-07-04 12:57:35

+0

这将严重依赖于你正在使用的数据库Postgres 8.0+和Oracle支持正确的事务处理MySQL不会与它们很好地协作,而大多数其他数据库根本不支持它们。所以问题之一是“你的数据库实际上是否支持交易?” – 2010-07-04 18:53:10

回答

4

为什么不能简单地做:

@transaction.commit_manually 
def save(self, *args, **kwargs): 
    try: 
     super(self.__class__, self).save(*args, **kwargs) 
     self.qa.vote_down_count += 1 
     self.qa.save() 
    except: 
     transaction.rollback() 
     raise 
    else: 
     transaction.commit() 

这是怎么the docs意味着这样做,但他们说,这样做在您的视图功能,所以你可能不需要@transaction.commit_manuallysave()方法,而不是把它的观点。

+1

在我看来,改变操作的顺序并不能解决问题,它不能防止错误发生,还有其他一些情况,比如self.qa.save()必须在之前完成。 commit_amually修饰器不会改变行为。 – 2010-07-04 13:06:40

+1

我有问题可以帮助我。你可以在这个链接找到我的问题https://stackoverflow.com/questions/29574699/how-can-i-save-the-whole-db-transaction-if-there-is-no-error-in-python @ mike-desimone – Krish 2015-04-11 07:14:17

3

尝试使用savepoints。就像这样:

def save(self, *args, **kwargs): 

try: 
    sid = transaction.savepoint() 
    self.qa.vote_down_count += 1 
    self.qa.save() 

    super(self.__class__, self).save(*args, **kwargs) 

except: 
    transaction.rollback(sid) 
    raise 
else: 
    transaction.commit(sid) 
+0

我想你的意思是savepoint_rollback和savepoint_commit,但它也不起作用。 – 2010-07-04 13:03:01

0

我认为Mike DeSimone的答案是正确的。

关于数据库,取决于您使用的MySQL版本(如果使用它),可能是您的数据库使用MyISAM引擎的表,它不支持事务。

要检查它只是在mysql的shell中运行:

SELECT TABLE_NAME, 
    ENGINE 
    FROM information_schema.TABLES 
    where TABLE_SCHEMA = 'your_db_name' ; 

你可以改变你的表到InnoDB和设置default_storage_engine在MySQL配置InnoDB的。 (这里的详细信息:http://parasjain.net/2010/06/08/how-to-switch-to-innodb-database-in-mysql/

之后交易应该工作。最好是使用Postgres,但如果你想使用MySQL/InnoDB,那么可能你需要一个解决方法来加载具有前向引用的灯具漏洞修复是已经存在于Django的树干,我也移植它的Django 1.3.1,请参阅Django 1.3.1.1 on Github)。