django执行并发操作时保证数据的一致性

 

https://blog.csdn.net/AyoCross/article/details/80874460

 


修改时间修改说明修改人
2018-06-03初次成稿AyoCross

1. 情景复现

本周一,我负责维护的一个公司内部django项目,出现了两次数据库死锁导致的系统不可用的情况,报错信息如下:

OperationalError: (1205, 'Lock wait timeout exceeded; try restarting transaction')
  • 1

报错描述
即:数据库资源被占用时间过长,导致超时。
出现问题之后赶紧找PE把数据库里的锁kill,然后再来定位问题,看sql语句执行的都没什么异常,而且系统最近也没有进行过更新。

项目使用的版本号:
django=1.8.3
mysql=5.5.47,死锁涉及的表为InnoDB

2. 问题分析

我们都知道,InnoDB数据表在执行update操作时,可以添加行锁,来确保修改数据时不会同时被其他人修改。我印象中,django中的ORM,应该是有对这个锁的封装的,所以一直都没有管过update数据时的可靠性问题。

出了这个问题以后,Google了一下,发现好像并没有相关的说明,互联网中绝大多数都是说,想要确保数据的一致性,需要使用select_for_update 来实现加锁。而且大都指向同一篇文章:国内翻译文/英文原文。但是我明明记得以前好像看过,django会自动为操作加锁,防止不同用户之间产生冲突。难道是我记忆出现了偏差?

3. 原因梳理

好吧,既然网上找的方案行不通,那就看源码吧,还好有pycharm这么好用的看源码工具,随便找到项目中一个Bean.save()的位置,摁住Ctrl,点击鼠标,进入调用源码的位置。然后就是找到生成SQL的位置了。经过一番的定位,最终,在

C:\Python27\Lib\site-packages\django\db\models\sql\compiler.py

这个文件里找到:
as_sql

在这个函数里,找到select for update相关的说明:

此处输入图片的描述

此处输入图片的描述

看这个源码的意思,还真是,除非你在代码里显式的注明,调用select_for_update,则会给执行的SQL语句加上FOR UPDATE,否则就不会有相关的操作。本以为自己想的肯定没问题,网上说的都是错的,结果被拍拍打脸,果然是自己的记忆出现了偏差,django对于并发数据的保护默认是不存在的,需要人为去干预才行,否则如果多人同时操作同一行数据,就会出问题。

4. 问题解决

至于这个问题应当如何解决,在上面两篇文章的下面都做了详细的解释,我在这就不赘述了,遇到类似问题的同学,可以跟着上面文章里的两种乐观/悲观的思路,去尝试解决。

--------------------- 本文来自 AyoCross 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/AyoCross/article/details/80874460?utm_source=copy

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值