sqlalchemy并发更新问题

时间:2014-02-08 23:54:26

标签: python mysql sql concurrency sqlalchemy

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

每次进程获得一个作业时,它“检出”该作业是否标记它已开始,因此没有其他进程可以对其进行操作。

我想要一个会话的单个进程能够:

  1. 找到排名最高的职位
  2. 将此作业的开始字段更新为当前时间戳
  3. 没有冒险任何其他会话也可能选择并开始排名最高的工作。其他会议也在任何特定时间改变排名。

    这是我的尝试:

    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的方式来做。我怎么能这样做?


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

2 个答案:

答案 0 :(得分:2)

锁定桌子并不好。您可以在选择时锁定行。

以下代码使用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次尝试后挽救?)。

答案 1 :(得分:-2)

你必须使用python锁。

这是一个很好的阅读,请看看。

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