V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
brickgao
V2EX  ›  Python

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

  •  
  •   brickgao ·
    brickgao · 2014-02-14 16:48:58 +08:00 · 11500 次点击
    这是一个创建于 3964 天前的主题,其中的信息可能已经有所发展或是发生改变。
    之前用 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()

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

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

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

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

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

    感谢 最后我还是尽量塞到一条去了 没用锁
    pubby
        11
    pubby  
       2014-02-15 23:23:54 +08:00 via Android
    如果业务更复杂点的原子操作,可以用mysql的GET_LOCK() RELEASE_LOCK()简单实现上锁,只要保证大家都连同一台mysql服务器就可以跨机器“集群锁”了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2930 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 13:23 · PVG 21:23 · LAX 05:23 · JFK 08:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.