简体   繁体   English

Flask-SQLAlchemy 不会始终如一地增加列

[英]Flask-SQLAlchemy doesn't increment column consistently

I've build small web app and noticed when there are multiple actions at the same time where it requires database to get last record it doesn't get newest results我已经构建了小型网络应用程序,并注意到当同时有多个操作需要数据库获取最后一条记录时,它不会获得最新结果

For example:例如:

add_amount = 1

record = Table.query.filter_by(id=1).first()

record.amount += add_amount
db.session.commit()

if multiple people add record in same time it won't get newest data如果多人同时添加记录,则不会获得最新数据

  • at 12:00:01 record.amount == 3 someone adds 1在 12:00:01 record.amount == 3 有人加 1
  • at 12:00:02 record.amount == 3 someone adds 1在 12:00:02 record.amount == 3 有人加 1
  • at 12:00:03 record.amount == 4 instead of 5在 12:00:03 record.amount == 4 而不是 5

What would be best solution to take care of it?照顾它的最佳解决方案是什么? create new db session?创建新的数据库会话?

What you're running into is called a race condition .您遇到的情况称为race condition It's a heavily studied subject within concurrency in general.总的来说,这是并发性中一个经过大量研究的主题。 It happens, for example, when the following order of operations occurs:例如,当发生以下操作顺序时,就会发生这种情况:

  • Process A fetches the row with ID 1 (amount = 10)进程 A 获取 ID 为 1 的行(数量 = 10)
  • Process A increments the amount (amount = 11)进程 A 增加金额(金额 = 11)
  • Process B fetches the row with ID 1 (amount = 10)进程 B 获取 ID 为 1 的行(数量 = 10)
  • Process A saves the updated amount (amount = 11)进程A保存更新后的金额(金额=11)
  • Process B increments the amount (amount = 11)进程 B 增加金额(金额 = 11)
  • Process B saves the updated amount (amount = 11)进程B保存更新后的金额(金额=11)

Now you can see that the change made by A has been overwritten completely.现在您可以看到 A 所做的更改已被完全覆盖。 There is no record that it ever happened and it did not influence the current value of amount .没有任何记录表明它曾经发生过,也没有影响amount的当前值。


As per this answer , you can apply a lock that will allow only one process to have the row fetched at a time, and the lock is released on db.session.commit() .根据这个答案,您可以应用一个,该一次只允许一个进程获取行,并在db.session.commit()上释放该锁。 The lock locks only that one row, so any other calls to any other records should be fine.锁只锁定那一行,所以对任何其他记录的任何其他调用都应该没问题。

record = Table.query.filter_by(id=1).with_for_update().first()

With the locking, the process would become:锁定后,过程将变为:

  • Process A tries to fetch the row with ID 1 and acquires the lock (amount = 10)进程 A 尝试获取 ID 为 1 的行并获取锁(数量 = 10)
  • Process A increments the amount (amount = 11)进程 A 增加金额(金额 = 11)
  • Process B tries to fetch the row with ID 1, but has to wait for the lock进程 B 尝试获取 ID 为 1 的行,但必须等待锁定
  • Process A saves the updated amount and releases the lock (amount = 11)进程A保存更新的数量并释放锁(数量=11)
  • Process B acquires the lock (amount = 11)进程 B 获取锁(数量 = 11)
  • Process B increments the amount (amount = 12)进程 B 增加金额(金额 = 12)
  • Process B saves the updated amount and releases the lock (amount = 12)进程B保存更新的数量并释放锁(数量=12)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM