很好的一天,
这是对我的旧帖子的更新
SQL Simultaneous transactions ignore each other's locks??? DEADLOCK [InnoDB, Python]
,因为我后来意识到这个问题与我认为的问题无关。我正在尝试为客户端创建与基于T-SQL的脚本等效的MySQL。
我有两个完全相同的脚本,
爱丽丝
和
巴里
同时运行。他们的目标是
-
SELECT * FROM job WHERE status = 0 LIMIT 1 FOR UPDATE
-
UPDATE job SET status = 1
在jobIDs匹配的地方,做一些其他的事情,然后。。。
-
COMMIT
更改,然后继续作业
我的问题是
爱丽丝
锁定,读取作业,
UPDATES
状态1,但一旦她做出改变,
巴里
获取锁并读取状态0,即原始状态。。。甚至Alice有时也会在她之后看到状态0
提交
这是我的python脚本中的一小段,但足以理解过程:
connection = MySQLdb.connect(host=..., user=..., [...])
cursor = connection.cursor(MySQLdb.cursors.DictCursor)
[...]
execute("START TRANSACTION")
execute("SELECT * FROM job WHERE status = %s LIMIT 1 FOR UPDATE", 0)
job_data = cursor.fetchone()
# debug("Made lock")
if not job_data:
connection.commit()
# debug("No rows")
else:
# debug("Locked row with status "+str(job_data['status']))
execute("SELECT status FROM job")
# debug("Double checked status is "+str(cursor.fetchone()))
execute("UPDATE job SET status = %s WHERE jobID = %s", 1, job_data['jobID'])
time.sleep(5)
execute("SELECT status FROM job")
# debug("Status before commit "+str(cursor.fetchone()))
connection.commit()
# debug('Committed')
execute("SELECT status FROM job")
# debug("Status after commit "+str(cursor.fetchone()))
这个臃肿的原始脚本版本充满了调试方法,可以尝试和理解正在发生的事情,包括
time.sleep
能够跟上正在发生的事情。我已经注释掉了本文摘录中的调试函数,以便于阅读实际发生的情况。
这些是
爱丽丝
和
巴里
:
爱丽丝
41,351161: Made lock
41,351161: Locked row with status 0
41,351161: Double checked status is {'status': 0}
46,352156: Status before commit {'status': 1}
46,370601: Committed
46,370601: Status after commit {'status': 1} (Sometimes Alice sees 0 here)
巴里
46,352682: Made lock
46,353184: No rows
48,365044: Made lock
48,365044: Locked row with status 0
48,365044: Double checked status is {'status': 0}
53,365062: Status before commit {'status': 1}
53,386910: Committed
53,388846: Status after commit {'status': 1}
输出开头的数字是时间戳,如下所示
SECONDS,MICROSECONDS
.
爱丽丝
锁上5秒钟,一旦她
COMMITS
,
巴里
拿走锁。然而,Barry看到状态为0(测试期间只有一行)。最终,双方都认为自己可以处理好这份工作。
我不知道为什么Barry在提交后读取到状态为0。是否已回滚?他是否正在读取旧值的缓存,从他调用
SELECT
? 不同的隔离级别会有帮助吗(似乎没有)?
当我在封闭环境中执行此代码时,
没有剩下的程序
,很有效!!!
巴里
当他最终拿到锁时,报告没有行。我不明白这有什么不同?我猜这意味着脚本的其他地方出了问题。但那会是什么呢?这是一个相当孤立的事务。使命感
提交
就在这段代码没有改变任何东西之前,我想可能之前的一个事务没有正确关闭。
爱丽丝
和
巴里
是测试时访问数据库的唯一进程(除了phpmyadmin)。
我在跑步
MariaDB
的InnoDB引擎
MySQLdb
(mysqlclient)作为Python的连接器。
AUTOCOMMIT
据我所知,他已经离开了。剧本很长,所以我只发了几行。在接下来的几天里,我将尝试将其分割开来,以尝试隔离问题,或者创建一个小的示例脚本。我似乎不知道如何让MariaDB打印出更改和锁定的日志,但如果我找到了,我会更新这篇文章。
任何想法、建议或评论都会令人惊叹。
祝你有美好的一天!