python - mysql python并发访问同一表列

标签 python mysql concurrency process

我已经探索了一些解决方案,但都没有取得太大的成功。我有两个 python 进程(使用子进程的 Popen 创建)和一个 mysql 表(称为 personone),其中包含一行两列:Age:0, id:1。一个进程选择该行,获取它的年龄并将其递增 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 作为存储引擎。

最佳答案

您正在创建一个 race condition .

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

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

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

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

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

关于python - mysql python并发访问同一表列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15351074/

相关文章:

python - 改变 Pandas 图的颜色条

python - 屏幕抓取 : getting around "HTTP Error 403: request disallowed by robots.txt"

mysql - 在 SQL 触发器中插入用户 ID

mysql - JOINing 表同时忽略重复项

MySQL ORDER BY Twice(按同一字段)

java - 测试线程程序

python - SyntaxError 无效 token

python - NoneType 和 str 不支持的操作数类型

javascript - 如何限制 Q Promise 并发?

c++ - 如何使用 Boost 库智能指针管理对象生命周期?