我使用transaction.atomic作为django 1.6中事务的上下文管理器。有一个代码块,我想在一个事务中,它有几个网络调用和一些数据库写入。我看到了非常奇怪的行为。每隔一次(可能每20次就有1次),我注意到没有任何异常地发生部分回滚,视图执行时没有任何错误。我的应用程序托管在heroku上,我们使用heroku postgres v9.2.8。伪码:
from django.db import transaction
def some_view(request):
try:
with transation.atomic():
network_call_1()
db_write_1.save(update_fields=['col4',])
db_write_2.save(update_fields=['col3',])
db_write_3.save(update_fields=['col1',])
network_call_2()
db_write_4.save(update_fields=['col6',])
db_write_5.bulk_create([object1, object2])
db_write_6.bulk_create([object1, object2])
except Exception, e:
logger.error(e)
return HttpResponse()我注意到的行为是,无一例外地引发,db写1-3回滚,其余经过,或db写1已回滚,rest已通过等等。我不明白为什么会发生这种事。首先,如果有回滚,它不应该是事务的完全回滚吗?如果存在回滚,是否也应该引发异常,以便我知道发生了回滚?每次发生这种情况,都不会引发任何异常,代码只是继续执行并返回一个成功的HttpResponse。
相关设置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'mydb',
'USER': 'root',
'PASSWORD': 'root',
'HOST': 'localhost',
'PORT': '5432',
},
}
CONN_MAX_AGE = None这个虫子几天来一直困扰着我。任何线索都会有很大帮助!
发布于 2014-03-09 19:23:59
经过几个小时的调试,我们找到了罪魁祸首。
当我们开始在金牛上申请的时候,它就产生了工人。向同一个工作人员发出的每个请求都使用相同的django DatabaseWrapper实例(在本例中是postgres),也称为连接。如果在一个请求中的事务中,工作人员要接收另一个请求,则此请求重置连接的状态,导致事务以意外的方式运行,如此bug中所述:https://code.djangoproject.com/ticket/21239有时事务没有提交,也没有引发任何异常以让您知道发生了什么。有时,当其他部分丢失时,它的部分确实会被提交,并且看起来像是部分回滚。
我们认为连接是线程安全的,但是这里的这一小块火绒修补魔法确保不是这样的:gunicorn.py#L16
如果可能的话,仍然愿意听取关于如何回避这个问题的建议。
编辑:不要使用run_gunicorn管理命令启动Django。它做了一些奇怪的修补,导致DB连接不安全。对我们有效的解决方案是只使用"gunicorn myapp.wsgi:application -c gunicorn.conf“。Django持久DB连接还不能使用gevent worker类型,所以除非您想要用完连接,否则不要使用它。
发布于 2014-03-03 18:02:35
不是Django专家,但我知道Postgres。我同意您的评估,即对于事务来说,这听起来是非常不典型的行为:回滚应该是全部的,或者是零的,并且应该有例外。既然如此,你能绝对肯定这是一种回滚式的情况吗?还有许多其他可能的原因,它们可能解释了数据库中出现的不同数据,而这些场景中的许多情况将更符合您观察到的回滚现象。
您还没有提供有关数据的任何细节,但我想象的是,您看到的是“我将col4的值设置为'foo',但是提交之后,旧的值'bar‘仍然在数据库中。”对吗?
如果是这样,那么其他可能的原因可能是:
以下只是几个让你开始学习的例子。还有很多其他可能的情况。有时候,调试问题的基本理念类似于DDT和pelicans的问题:因为数据库处于食物链的顶端,所以你经常可以看到那些问题--尽管它们似乎是数据库问题--实际上是在解决方案的其他地方引起的。
祝你好运,希望这能帮上忙!
发布于 2014-03-06 12:58:25
https://stackoverflow.com/questions/22053846
复制相似问题