SQL同步事务忽略彼此的锁???死锁[InnoDB,Python]

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

你好

我碰到了一个烧头。我的客户机要求我重新调整python程序的用途,以使用MySQL而不是Microsoft的SQL Server。我在SQL中找不到等效的解决方案

我似乎无法在一行上创建正确的更新锁。当两个相同的事务同时执行时,它们都读取行,尽管在序列化隔离级别打开了一个事务,并且使用SELECT。。。更新

也许我的代码可以更好地解释它:

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的输出。谢谢