Flask-SQLAlchemy中的with_for_update()行锁

16

我有一个名叫 "User" 的模型,其中包含 "Money" 字段。
存在这样一种情况:多个会话可以同时读取模型 "User" 并更新 "Money" 字段。

第二个会话应该在第一个会话成功更新后读取 "Money" 值。
我尝试在更新时锁定 "User" 行。
以下是我的代码:

user = User.query.with_for_update().filter_by(id=userid).first()
print('000000')
before_money = user.money
print('111111')
time.sleep(1)
user.money -= 0.1
print('User:' + str(user.id) + '***' + str(before_money) + '-' + str(0.1) + ' = ' + str(user.money))
time.sleep(1)
db.session.commit()
print('22222')

我同时打开了两个会话来运行这段代码,输出结果为

000000
111111
User:1***125.3-0.1 = 125.2
000000
111111
22222
User:1***125.3-0.1 = 125.2
22222

第二个会话没有读取更新后的值。

我真的很想知道问题出在哪里。

2个回答

25

我经过一整天的奋斗,终于找到了问题所在。

user = User.query.with_for_update().filter_by(id=userid).first()

应该是这样的

result = db.session.query(User.money).with_for_update().filter_by(id=userid).first()
money = result[0]
user.money = money - 0.1

是的,非常简单但令人讨厌


2
不是“烦人的”,只是“合乎逻辑”:查询是一个函数,要在它上面请求“for update”会感觉很奇怪... 在结果(实际查询)上执行这个操作更有意义。请注意,我认为您也可以在筛选器之后添加它(因为这些函数返回查询)。 - hl037_
1
@hl037 我认为他应该在过滤器之后添加它们,因为他这样做会锁定整个表(至少我是这么认为的)。 - juan
1
@juan 根据我的测试,这没有任何区别。 - Daocheng
3
你在user.money = money - 0.1中的'user'是从哪里得来的?请翻译这句话。 - Ravi verma
对于任何想要确保原子行更新的人来说,这是适合我的解决方案。 - JSON_Derulo

7

你只需要说明你想要锁定的内容:

user = User.query.with_for_update(of=User).filter_by(id=userid).first()
user.money -= 0.1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接