我有以下代码覆盖模型的save方法:
@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加1,但如果在super(self)save方法中发生任何异常,则事务回滚(这意味着self.qa.vote_down_count + = 1未提交)在数据库中)。
实际行为是:即使IntegrityError异常从超级(自我)保存引发,self.qa.vote_down_count + = 1也会提交到数据库。
有没有?
答案 0 :(得分:6)
为什么不简单地做:
@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_manually
方法上的save()
,而是放置它在视图上。
答案 1 :(得分: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)
答案 2 :(得分:1)
我认为Mike DeSimone的答案是对的。
关于数据库,根据您使用的MySQL版本(如果使用它),可能是您的数据库使用的MyISAM引擎表不支持事务。
要检查它只是在mysql shell中运行:
SELECT TABLE_NAME,
ENGINE
FROM information_schema.TABLES
where TABLE_SCHEMA = 'your_db_name' ;
您可以将表更改为InnoDB,并在MySQL配置中将default_storage_engine设置为innodb。 (详情请见http://parasjain.net/2010/06/08/how-to-switch-to-innodb-database-in-mysql/。
之后交易应该有效。最好使用Postgres,但是如果你想使用MySQL / InnoDB,那么你可能需要一个解决方法来加载具有前向引用的fixtures(Django Trunk中已经存在BugFix,我也将它移植到Django) 1.3.1,见Django 1.3.1.1 on Github)。