【问题标题】:Python hangs on MySQL UpdatePython 挂在 MySQL 更新上
【发布时间】:2016-07-19 20:03:33
【问题描述】:

我已经研究了一段时间了,在互联网上搜索并没有找到解决方案。

我想在访问数据库之前检查其他进程是否正在访问我的数据库。我有一个列 id 和 state 的表。如果 state 为 1 那么我想将其更改为 0 并继续访问,否则我想不管它。下面是我的代码,我不明白为什么它不起作用但每次都挂在此处的最后一行cursor.execute(set_lock)

get_lock = "SELECT state FROM running WHERE id=1"
cursor.execute(get_lock)
result = cursor.fetchall()
if(result[0][0]):
    set_lock = "UPDATE running SET state=0 WHERE id=1"
    cursor.execute(set_lock)

我很确定这与光标的重用有关,但我不明白为什么会出现问题,我之前已经成功完成过。任何帮助你都很棒。

干杯


我以为我已经解决了问题,但修复很不稳定,它似乎开始工作,但随后开始返回错误的状态。在 PHPMyAdmin 中运行 MySQL 语句,它应该返回 1,但在打印结果时它返回 0,因此跳过了 if 语句的内容。

cursor.execute("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;")
get_lock = "SELECT state FROM running WHERE id=1;"
cursor.execute(get_lock)
result = cursor.fetchall()
if(result[0][0]):
    set_lock = "UPDATE running SET state=0 WHERE id=1;" //Lock
    cursor.execute(set_lock)
    cursor.execute("COMMIT;")

    ---- DO WHAT I NEED TO DO ----

    set_lock = "UPDATE running SET state=1 WHERE id=1;" //Unlock
    cursor.execute(set_lock)
    cursor.execute("COMMIT;")

cursor.execute("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;")
cursor.close()

有什么想法吗?

【问题讨论】:

  • 您应该同时阅读stackoverflow.com/questions/10935850/…。根据您的事务隔离,您当前的实现可能会针对竞争条件开放。
  • 谢谢,为我提供解决方案。
  • 选择更新和更新后,您需要通过提交释放行锁。否则另一个 select for update 将阻塞等待行锁。

标签: python mysql cursor


【解决方案1】:

感谢Ilja's 评论的以下线索,找到了解决方案。

get_lock = "SELECT state FROM running WHERE id=1 FOR UPDATE;"
cursor.execute(get_lock)
result = cursor.fetchall()
if(result[0][0]):
    set_lock = "UPDATE running SET state=0 WHERE id=1;"
    cursor.execute(set_lock)
    cursor.execute("COMMIT;")

由于SELECT 语句中的拼写错误,最初这不起作用。最后一句话也很重要cursor.execute("COMMIT;")

阅读此question 后,我似乎有一个解决方案,但它的行为是断断续续的。

cursor.execute("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;")
get_lock = "SELECT state FROM running WHERE id=1;"
cursor.execute(get_lock)
result = cursor.fetchall()
if(result[0][0]):
    set_lock = "UPDATE running SET state=0 WHERE id=1;" //Lock
    cursor.execute(set_lock)
    cursor.execute("COMMIT;")

    ---- DO WHAT I NEED TO DO ----

    set_lock = "UPDATE running SET state=1 WHERE id=1;" //Unlock
    cursor.execute(set_lock)
    cursor.execute("COMMIT;")

cursor.execute("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;")
cursor.close()

【讨论】:

  • 我的意思是你应该使用SELECT ... FOR UPDATE。使用READ UNCOMMITTED,您确实获得了更新的值(通过脏读),如果另一个进程设法在另一个进程中的SELECT 之前发出UPDATE,但仍然有一个小的时间窗口,两个进程都可能@987654331 @,看到锁没有设置,然后发出 2 UPDATEs 并继续认为他们获得了锁。
  • 我阅读它的方式引导我使用READ UNCOMMITTED 方法。我明白你在说什么。我会看看情况如何,但请记住您是 cmets。感谢您的帮助。
猜你喜欢
  • 2019-03-18
  • 2014-10-10
  • 2019-04-20
  • 2018-04-02
  • 1970-01-01
  • 2023-03-31
  • 2013-11-04
  • 1970-01-01
  • 2018-10-13
相关资源
最近更新 更多