首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >django 1.6.1中事务的奇怪行为

django 1.6.1中事务的奇怪行为
EN

Stack Overflow用户
提问于 2014-02-26 21:34:04
回答 4查看 1.8K关注 0票数 6

我使用transaction.atomic作为django 1.6中事务的上下文管理器。有一个代码块,我想在一个事务中,它有几个网络调用和一些数据库写入。我看到了非常奇怪的行为。每隔一次(可能每20次就有1次),我注意到没有任何异常地发生部分回滚,视图执行时没有任何错误。我的应用程序托管在heroku上,我们使用heroku postgres v9.2.8。伪码:

代码语言:javascript
复制
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。

相关设置:

代码语言:javascript
复制
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'mydb',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': 'localhost',
        'PORT': '5432',
    },
}
CONN_MAX_AGE = None

这个虫子几天来一直困扰着我。任何线索都会有很大帮助!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 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类型,所以除非您想要用完连接,否则不要使用它。

票数 5
EN

Stack Overflow用户

发布于 2014-03-03 18:02:35

不是Django专家,但我知道Postgres。我同意您的评估,即对于事务来说,这听起来是非常不典型的行为:回滚应该是全部的,或者是零的,并且应该有例外。既然如此,你能绝对肯定这是一种回滚式的情况吗?还有许多其他可能的原因,它们可能解释了数据库中出现的不同数据,而这些场景中的许多情况将更符合您观察到的回滚现象。

您还没有提供有关数据的任何细节,但我想象的是,您看到的是“我将col4的值设置为'foo',但是提交之后,旧的值'bar‘仍然在数据库中。”对吗?

如果是这样,那么其他可能的原因可能是:

  • 有时,用来设置'foo‘值的代码实际上是在设置现有的'bar’值,或者是空值。
  • 代码正在设置'foo‘值,但是有一个数据访问层(也称为DAL),它带有未设置的“脏”标志(例如,如果对象处于断开连接的状态),因此,当提交完成时,DAL不会将其视为应该写入的更改。

以下只是几个让你开始学习的例子。还有很多其他可能的情况。有时候,调试问题的基本理念类似于DDT和pelicans的问题:因为数据库处于食物链的顶端,所以你经常可以看到那些问题--尽管它们似乎是数据库问题--实际上是在解决方案的其他地方引起的。

祝你好运,希望这能帮上忙!

票数 1
EN

Stack Overflow用户

发布于 2014-03-06 12:58:25

我的3美分:

例外情况

我们确定没有例外。但我们是吗?您的伪代码只是通过日志记录来“处理”异常。确保没有loggingpass在其他地方“处理”的异常。

部分回滚

我们预计整个事务将被回滚,而不仅仅是一部分。因为django 1.6嵌套原子事务创建了一个保存点并回滚回到了最后一个保存点。确保没有嵌套的事务。也许您有交易中间件、active check、请求。也许事务是在这些network_call函数中启动的。

再生产

因为network_call代码可能会阻塞。尝试用模拟调用替换它们,超时(可能不在生产中)。如果这导致100% (部分)回滚。它应该使定位部分回滚的问题更容易。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22053846

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档