【问题标题】:mysql python concurrent access on same table columnmysql python并发访问同一表列
【发布时间】:2013-03-12 00:19:09
【问题描述】:

我探索了一些解决方案,但没有取得多大成功。我有两个 python 进程(使用 Popen 从子进程创建)和一个 mysql 表(称为persone),其中包含一行两列:Age:0, id:1。一个进程选择该行,获取它的年龄并将其递增一。它这样做了 1000 次。第二个做同样的事情,但减少它。我并行运行每个进程。

理论上,我希望最终年龄保持为零。问题是我在 mymain.py 的末尾不断获得 100 到 -100 之间的随机值,我猜这意味着有同时完成的访问,破坏了数据库。我想知道我错过了什么?

这是我用来测试的代码:

ajoutAge.py

import MySQLdb as lite

num=1000
connexion = lite.connect(host="localhost", user="root", passwd="123", db="test")
with connexion:
    for i in range(num):
       cur = connexion.cursor()
       cur.execute('start transaction')
       cur.execute('select Age from persone where id=1')
       age = cur.fetchone()[0]
       cur.execute('update persone set Age='+str(age+1)+' where id=1')
       # cur.execute('rollback')
       cur.execute('commit')
print "ajout Done"

retraitAge.py

import MySQLdb as lite

num=1000
connexion = lite.connect(host="localhost", user="root", passwd="123", db="test")
with connexion:
    for i in range(num):
        cur = connexion.cursor()
        cur.execute('start transaction')
        cur.execute('select Age from persone where id=1')
        age = cur.fetchone()[0]
        cur.execute('update persone set Age='+str(age-1)+' where id=1')
        cur.execute('commit')
print "retrait Done"

mymain.py

from subprocess import Popen

a=Popen("python ajoutAge.py", shell=True)
aa=Popen("python ajoutAge.py", shell=True)
b=Popen("python retraitAge.py", shell=True)
bb=Popen("python retraitAge.py", shell=True)

a.communicate()
aa.communicate()
b.communicate()
bb.communicate()
print "Main done"

我的表使用 InnoDB 作为存储引擎。

【问题讨论】:

    标签: python mysql concurrency process


    【解决方案1】:

    您正在创建一个race condition

    每次您选择当前年龄时,都会在该年龄和您的 UPDATE 之间有一瞬间。在那一瞬间,另一个过程可能(显然有时是)更新值。

    所以在第一个过程中,当您将值更新为 age+1 时,它会根据稍微过时的值递增。

    要解决此问题,您有几个选择:

    • SELECT ... FOR UPDATE,锁定行,防止其他进程在您完成事务之前对其进行修改。你需要确保你没有提交你的 SELECT 事务,这会释放锁,允许另一个竞争条件。

    • UPDATE persone SET age = age+1 WHERE id=1(当然是age=age-1)。换句话说,在您更改值的同一表达式中读取值,因此它是原子的,没有并发进程可以“潜入”并在两者之间进行更改。

    【讨论】:

    • 哇,我很想在学校学习。谢谢!我想我仍然需要第一个选项的交易,但不是第二个,对吗?
    • 对,对于第一个选项,您需要确保 SELECT 和 UPDATE 在同一个事务中运行,因此它会保持锁定直到您完成该行。
    • PS:如果你获得了 Comp Sci 学位而没有接触到竞赛条件的概念,那么你就被骗了。
    • 哦,别担心,我知道比赛条件!我根本不知道如何用 Mysql 处理它;)再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多