gpt4 book ai didi

python - SELECT...FOR UPDATE 在提交后选择旧数据

转载 作者:行者123 更新时间:2023-11-29 17:54:35 27 4
gpt4 key购买 nike

美好的一天,

这是我旧帖子的更新:SQL Simultaneous transactions ignore each other's locks??? DEADLOCK [InnoDB, Python] ,后来我意识到这个问题与我认为的问题无关。我正在尝试为客户端创建相当于基于 T-SQL 的脚本的 MySQL。

我有两个相同的脚本,AliceBarry 同时运行。他们的目标是

  1. 从作业中选择 *,其中状态 = 0 LIMIT 1 FOR UPDATE
  2. UPDATE job SET status = 1,其中 jobID 匹配,执行一些其他操作,然后...
  3. 提交更改,并继续工作

我遇到的问题是,Alice 进行锁定,读取作业,更新 将其状态为 1,但是一旦她提交更改, Barry 占用锁并读取状态 0,即原始状态...甚至 Alice 有时在她 COMMIT

后也会看到状态 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 来跟上正在发生的事情。我已注释掉此摘录中的调试函数,以便更轻松地阅读实际发生的情况。
这些是 AliceBarry 的输出:

爱丽丝

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

Alice 持有锁五秒钟,一旦她 COMMITSBarry 就获得了锁。然而,Barry 看到状态为 0(测试期间只有一行)。最终双方都认为他们可以处理这项工作。

我不确定为什么 Barry 在提交后读取状态为 0。是回滚了吗?他是否正在读取调用 SELECT 时的旧值的缓存?不同的隔离级别会有帮助吗(似乎没有)?

当我在封闭环境中执行此代码时,没有程序的其余部分,它可以工作! Barry 一旦最终获得锁,就不会报告任何行。我不明白它有什么不同?我猜这意味着脚本中的其他地方出了问题。但它可能是什么?这是一个相当孤立的交易。在此代码之前调用 COMMIT 不会改变任何内容,我想也许之前的事务没有正确关闭。
AliceBarry 是测试时唯一访问数据库的进程(除了 phpmyadmin)。

我正在运行 MariaDB 的 InnoDB 引擎,并使用 MySQLdb (mysqlclient) 作为 Python 连接器。据我所知,AUTOCOMMIT已关闭。剧本很长,所以我只发了几行。我将在接下来的几天内尝试将其分开,以尝试隔离问题,或创建一个小示例脚本。我似乎不知道如何让 MariaDB 打印出更改和锁定的日志,但如果我这样做了,我会更新这篇文章。

任何想法、建议或评论都会很棒。

祝你有美好的一天!

最佳答案

按照Solarflare关于一点点分割程序的建议后,我最终发现了导致代码远程部分的问题,该部分运行正常,没有错误,但在运行后完全不同从 T-SQL 迁移到 SQL。

我一开始以为是 SQL 服务器的问题,但这只是一个严重的错误。由于某种原因,我现在遇到了可怕的僵局,这是另一个值得研究的乐趣。

感谢您的评论以及您花时间解释可能出现的问题,很抱歉这只是一个个人愚蠢的问题

祝你有美好的一天!

关于python - SELECT...FOR UPDATE 在提交后选择旧数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48974420/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com