42

我正在寻找一个在 SQLAlchemy 中使用 select 进行更新的完整示例,但没有找到一个谷歌搜索。我需要锁定一行并更新一列,以下代码不起作用(永远阻塞):

s = table.select(table.c.user=="test",for_update=True)
# Do update or not depending on the row
u = table.update().where(table.c.user=="test")         
u.execute(email="foo") 

我需要提交吗?我怎么做?据我所知,您需要:开始事务选择...用于更新更新提交

4

3 回答 3

47

如果您使用的是 ORM,请尝试使用with_for_update函数:

foo = session.query(Foo).filter(Foo.id==1234).with_for_update().one()
# 该行现在被锁定

foo.name = '酒吧'
session.add(foo)

session.commit()
# 此行现在已解锁
于 2017-03-04T22:32:35.633 回答
16

迟到的答案,但也许有人会觉得它有用。

首先,您不需要提交(至少不需要在查询之间,我假设您正在询问)。您的第二个查询无限期挂起,因为您正在有效地创建到数据库的两个并发连接。第一个是获取选定记录的锁定,然后第二个尝试修改锁定的记录。所以它不能正常工作。(顺便说一下,在给出的示例中,您根本没有调用第一个查询,所以我假设在您的真实测试中您在s.execute()某处做了类似的事情)。因此,工作实现应该看起来更像:

s = conn.execute(table.select(table.c.user=="test", for_update=True))
u = conn.execute(table.update().where(table.c.user=="test"), {"email": "foo"})
conn.commit()

当然,在这种简单的情况下,没有理由进行任何锁定,但我想这只是示例,您计划在这两个调用之间添加一些额外的逻辑。

于 2013-08-09T10:40:54.257 回答
3

是的,您确实需要提交,您可以在 上执行或明确Engine创建。Transaction修饰符也在values(...)方法中指定,而不是execute

>>> conn.execute(users.update().
...              where(table.c.user=="test").
...              values(email="foo")
...              ) 
>>> my_engine.commit()
于 2012-04-10T07:26:46.690 回答