• django autocommit的一个坑,读操作的事务占用导致锁表


    版权归作者所有,任何形式转载请联系作者。
    作者:petanne(来自豆瓣)
    来源:https://www.douban.com/note/580618150/

    缘由:有一个django守护进程Daemon一直在后台运行,轮询读数据库,导致被锁无法ALTER表结构。
    涉及django==1.4 django==1.9 mysql

    在1.4中(1.5之前版本均为这样),默认的transaction为autocommit,在读写数据库时,均会对数据表产生一个状态为RUNNING的事务,写操作在save的时候会触发autocommit,结束该事务,但是读操作不会触发autocommit,导致该事务一直RUNNING,并且不能对表结构进行操作。

    注:1.6之前的autocommit只对写操作有效,对读操作无效!
    注:1.6之前的autocommit只对写操作有效,对读操作无效!
    注:1.6之前的autocommit只对写操作有效,对读操作无效!

    先看看这个很有趣的例子,复现方式:
    1.在django的python shell 环境下执行一条读语句
    python manage.py shell
    >>User.objects.get(id=1)
    <User: xxxxx>

    2.在mysql shell里执行
    >>use information_schema;
    >>select * from INNODB_TRX G;
    此时,可以看到有一个RUNNING的事务
    >>show processlist;
    此时,可以看到process里有一个Id字段为上面事务的trx_mysql_thread_id的process,然后看该process的Host字段(通信的客户端IP和端口),可以确定此事务即为1步骤读操作占用。

    3.退出1中的python shell,可发现2中RUNNING的事务被结束。

    也就是说,守护进程Daemon一直运行不退出的话,只要里面有读操作,就会因为事务占用一直锁住这个表。同理,每次web请求,使用ORM读的时候,也是这样,但web请求结束django关掉数据库连接,就会结束该事务。

    解决方法:
    在django==1.5版本之前,在Daemon里每次执行完读操作后,都手动commit一下
    方法1:
    >>from django.db import transaction
    >>User.objects.get(id=1)
    >>transaction.commit()
    方法2:将查询语句置于事务管理commit_on_success的block下,顾名思义,其作用为在block中的代码执行完毕且无Exception的时候自动commit
    >>with transaction.commit_on_success():
            User.objects.get(id=1)

    django==1.6版本,在settings.py的数据库配置项DATABASES中,添加了"AUTOCOMMIT"参数,默认为True,详见文档https://docs.djangoproject.com/en/dev/ref/settings/#autocommit,即为所有操作自动提交。
    另外注意在1.6 至 1.6.2版本中,该参数有BUG,会导致AUTOCOMMIT不生效,django在1.6.2版本fix了该BUG,详见https://docs.djangoproject.com/en/1.10/releases/1.6.2/

  • 相关阅读:
    使用异或解题 —— 序列中仅出现一次的两个数
    使用异或解题 —— 序列中仅出现一次的两个数
    希尔排序
    java中接口的定义与实现
    erlang工作前新手学习指引路线
    NAT的全然分析及其UDP穿透的全然解决方式
    hibernate官方新手教程 (转载)
    git与svn的不同
    C#调用GDAL算法进度信息传递
    atitit. access token是什么??微信平台公众号开发access_token and Web session保持状态机制
  • 原文地址:https://www.cnblogs.com/ExMan/p/9340415.html
Copyright © 2020-2023  润新知