【问题标题】:sqlalchemy concurrency update issuesqlalchemy 并发更新问题
【发布时间】:2014-02-08 23:54:25
【问题描述】:

我在 MySQL InnoDB 数据库中有一个表 jobs,其中包含字段 idrank 和日期时间 started

每当一个进程获得一个作业时,它都会“签出”该作业以将其标记为已启动,这样其他进程就不会对其进行处理。

我希望一个带有会话的进程能够:

  1. 找到排名最高的工作
  2. 将此作业的开始字段更新为当前时间戳

不冒任何其他会话也可能选择并开始排名最高的工作的风险。其他会议也在随时改变排名。

这是我的尝试:

session.execute("LOCK TABLES jobs READ")
next_job = session.query(Jobs).\
    filter(Jobs.started == None).\
    order_by(Jobs.rank.desc()).first()

# mark as started
smt = update(Jobs).where(Jobs.id == next_job.id).\
    values(started=datetime.now())
session.execute(smt)
session.execute("UNLOCK TABLES")

但这失败了:

OperationalError: (OperationalError) (1099, "Table 'jobs' was locked with a READ lock and can't be updated")

无论如何,我宁愿以 SQLAlchemy 提供的更 Pythonic 的方式来做这件事。我该怎么做?


编辑:澄清一下,我说的是数据库中的读/写并发,而不是线程/进程同步。我的工人将分布在一个网络中。

【问题讨论】:

    标签: python mysql sql concurrency sqlalchemy


    【解决方案1】:

    锁表不好。选择时可以锁定行。

    以下代码使用with_lockmode():

    try:
        job = session.query(Jobs).with_lockmode('update').filter(
             Jobs.started == None).first()
        # do something
        session.commit()
    except Exception as exc:
        # debugs an exception
        session.rollback()
    

    您可能希望将其放入 while 循环并重试几次(并在 77 次尝试后退出?)。

    【讨论】:

    • 方法.with_update_for()实际上是你最终需要使用的。
    • 你的意思是with_for_update
    • 马太福音 18:22 - '耶稣对他说:“我不是对你说,最多七次,而是最多七十次。”
    【解决方案2】:

    你将不得不使用 python 锁。

    这是一本好书,请看一下。

    http://effbot.org/zone/thread-synchronization.htm

    【讨论】:

    • 不,我说的是数据库级别的锁定。我的进程在不同的机器上。我澄清了这个问题。
    猜你喜欢
    • 1970-01-01
    • 2013-06-05
    • 2013-05-19
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多