如何保证并发下数据库操作的原子性?

2014-02-14 16:48:58 +08:00
 brickgao
之前用 Flask 和 Flask-SQLAlchemy 做了一个小应用,数据库用的是 MySQL。

后来在 SAE 上做测试的时候发现并发稍稍高点的时候数据库就会出现问题。

例如我定义一个模型event,其中有一个整型列total。

然后定义如下操作:

_event = event.query.get(1)
if _event.total < 100:
_event.total += 1
else:
#balabala
db.session.commit()
db.session.close()

请问在并发状况下这样做是否安全?如果不安全的话应该怎么修改。
11245 次点击
所在节点    Python
11 条回复
BOYPT
2014-02-14 16:55:21 +08:00
显然不是安全的,应该get查询的时候就判断了数值。
brickgao
2014-02-14 16:58:32 +08:00
@BOYPT 那_event.total += 1这个自加操作会不会粗问题?
BOYPT
2014-02-14 17:05:20 +08:00
@brickgao 当然有问题啊,.get()完了之后数值就在程序内存了,无法保证数据库里面的total还是你查到那个。

这种情况要么你把这个逻辑做到sql的查询里面,要么改下你的算法,用个原子内存数值来做判断。
brickgao
2014-02-14 17:17:29 +08:00
@BOYPT 谢谢 我去想想看
loading
2014-02-14 17:23:43 +08:00
sql里写 sum(xx)+1 不就好了,

你还浪费一次查询…
hepochen
2014-02-14 17:29:20 +08:00
除非你自己处理全局锁(跨各个进程、线程)的,不然就不应该把原子操作放在程序中处理;这个太复杂了。

放在数据库中操作,让它们自己处理吧。
dorentus
2014-02-14 17:30:30 +08:00
话说,不知道你的实际需求是什么
其实很多时候,去掉 if total < 100 这个判断,每次都累加
然后再你需要用到 total 的时候,再做这个判断,比如 display (total if total < 100 else total)这样貌似也是可行的吧……
brickgao
2014-02-14 18:04:46 +08:00
@loading 我就是打个比方 其实不是总和...

@dorentus 我去试试看 准备把相关的操作尽量塞到一条语句里了
yaroot
2014-02-14 22:33:15 +08:00
brickgao
2014-02-15 00:22:44 +08:00
@yaroot
@hepochen

感谢 最后我还是尽量塞到一条去了 没用锁
pubby
2014-02-15 23:23:54 +08:00
如果业务更复杂点的原子操作,可以用mysql的GET_LOCK() RELEASE_LOCK()简单实现上锁,只要保证大家都连同一台mysql服务器就可以跨机器“集群锁”了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/100244

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX