SQL同步事务忽略彼此的锁???死锁[InnoDB,Python]
你好 我碰到了一个烧头。我的客户机要求我重新调整python程序的用途,以使用MySQL而不是Microsoft的SQL Server。我在SQL中找不到等效的解决方案 我似乎无法在一行上创建正确的更新锁。当两个相同的事务同时执行时,它们都读取行,尽管在序列化隔离级别打开了一个事务,并且使用SELECT。。。更新 也许我的代码可以更好地解释它:SQL同步事务忽略彼此的锁???死锁[InnoDB,Python],python,sql,transactions,mariadb,database-deadlocks,Python,Sql,Transactions,Mariadb,Database Deadlocks,你好 我碰到了一个烧头。我的客户机要求我重新调整python程序的用途,以使用MySQL而不是Microsoft的SQL Server。我在SQL中找不到等效的解决方案 我似乎无法在一行上创建正确的更新锁。当两个相同的事务同时执行时,它们都读取行,尽管在序列化隔离级别打开了一个事务,并且使用SELECT。。。更新 也许我的代码可以更好地解释它: execute("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE") execute("START TRANS
execute("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE")
execute("START TRANSACTION")
execute("SELECT * FROM job WHERE status = %s LIMIT 1 FOR UPDATE", jobStatus.imported)
job_data = cursor.fetchone()
if not job_data:
connection.rollback()
else:
execute("UPDATE job SET status = %s WHERE jobID = %s", jobStatus.ingesting, job_data['jobID']) # Update the job data
if job_data['jobUUID'] == None:
job_data['jobUUID'] = new_unused_uuid().bytes
execute("UPDATE job SET jobUUID = %s WHERE jobID = %s LIMIT 1", job_data['jobUUID'], job_data['jobID'])
if job_data['dateAdded'] == None:
job_data['dateAdded'] = datetime.datetime.now()
execute("UPDATE job SET dateAdded = %s WHERE jobID = %s LIMIT 1", job_data['dateAdded'], job_data['jobID'])
execute("INSERT INTO ingestJob (fk_jobUUID, fk_nodeUUID, status) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE fk_nodeUUID = %s, status = %s", job_data['jobUUID'], unique_id.bytes, smallJobStatus.running, unique_id.bytes, smallJobStatus.running)
connection.commit()
程序如下:
选择一个可能的作业,其中包含要更新的作业
回滚如果没有作业,请释放锁,或者。。。
…更新行,使其无法重新选择,进行一些不相关的更改
犯罪
他们都做自己的事情,忽略对方的锁和事务
让我害怕的是它是随机的。它几乎每隔一次就发生一次。在一个隔离的环境中尝试相同的查询时,只要有足够的延迟,我就会得到我想要的确切结果。
一旦选择。。。由于更新是由Alice调用的,Barry无法读取该行,并挂起,直到Alice提交或回滚。我的现象要求在同一程序的两个实例之间同时执行
我尝试在第4行打印获取的行,它们返回完全相同的行。。。我在Ubuntu服务器上使用带InnoDB引擎的MariaDB 10.1.30,使用Python和MySQLdb mysqlclient模块进行通信。是玛丽亚吗?我认为它可能是比MySQL更好的选择
其中一个引发了一个例外,因为它正在和另一个太慢的noob争夺资源
正在进行事务处理和锁定
为了显示进行了FOR更新锁和正确的事务,我进行了以下测试。我同时运行了这个小poke脚本,同时在主脚本上的commit之前添加time.sleep10,以使锁保持至少10秒的活动状态
while True:
cursor.execute("SELECT * from job FOR UPDATE")
print('Selected')
time.sleep(1)
connection.rollback()
print('Released')
time.sleep(1)
一旦主脚本获得锁,小的poke脚本就会挂起,无法选择行。十秒钟后,poke脚本获得锁,但两个节点都再次执行!!!。正如您所看到的,顶部的一个抱怨死锁,因为底部的一个已经在事务中的其他地方插入了一行
我对其他更正确的SQL解决方案持开放态度。也许我做错了。在T-SQL中,可以更新一行并使用OUTPUT子句返回修改后的行,就像更新后运行了SELECT语句一样。我唯一的解决方案是选择一行进行更新,然后运行更新。我还没有真正考虑过使用过程,将其从Python中删除并在MariaDB上运行会更好吗
如果有任何提示或建议,我将不胜感激。我对SQL没有太多的经验,但离开SQL Server的行为尤其令人痛苦。由于我的客户希望使用dockers,我担心这不仅是一种不太可能的情况,而且是一种可能性,因为当产生极端负载时,可能会同时创建dockers
谢谢,祝你今天愉快 选择。。。FOR UPDATE根据您的配置在不同级别隔离事务。你可以在这里找到更多信息
但是代码中最重要的一点是,您必须为不同的事务使用不同的会话
如本文所述。如果在事务完成之前在同一会话中运行另一个事务,它将被隐式提交,这将导致代码中出现随机结果
您现在在代码中所做的与在一个终端中运行两个事务是一样的,这与在非事务中运行所有事务没有太大区别
您需要通过池等方法在不同的连接中创建事务,以模拟不同的会话。在事务的不同部分添加一些time.sleep语句后,我意识到问题与Alice和Barry同时执行或忽略对方的锁无关
如果没有睡眠记录,很快就看不出发生了什么。真正的问题是巴里在他的选择中阅读旧数据。。。对于更新,即使在Alice提交更新作业状态后,也会让他在Alice释放锁后立即执行相同的作业
由于这是一个完全不同的问题,我在这里用不同的解释和更相关的代码示例重新发布了这个问题:
很抱歉,这帮不了你。我自己还没有找到问题。这可能无法解决您的问题,但这是一个不适合评论的建议 一次执行所有更新:
UPDATE job SET
status = %s,
jobUUID = IFNULL(jobUUID, UUID()),
dateAdded = IFNULL(dateAdded, NOW())
WHERE jobID = %s
LIMIT 1
您可以通过使用LAST_INSERT_IDjobID来获取jobID,从而避免选择。Hi,据我所知,这两个程序都在各自的会话中运行,由一个批处理文件调用start py node.py两次启动。
此图显示并行运行的程序的两个实例。它们作为单独的进程运行,并使用相同的凭据与数据库建立自己独特的连接。这正是我所寻找的替代方案,以取代我从T-SQL的输出。谢谢