Array.pop 竞争条件
Array.pop Race Condition
3个系统用户同时点击购票
型号
class TicketInventory < ActiveRecord::Base
serialize :ticket_roll, Array
end
ticket_roll 以一系列数字作为种子
控制器
ticket_inventory = TicketInventory.find(1)
ticket_roll = ticket_inventory.ticket_roll
TicketInventory.transaction do
@ticket = ticket_roll.pop
ticket_inventory.save
end
他们都拿到了同一张票。
我考虑过 lock_version
,但这会引发错误,而不是提供下一张票。
我也查看了索引,但这需要每张票一行。
如何避免这种竞争情况?
您是否尝试使用 ActiveRecord::Locking::Pessimistic。它使用事务和数据库锁。根据文档,PostgreSQL 和 MySQL 支持它:
MySQL: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
你可以这样使用:
ticket_inventory = TicketInventory.find(1)
ticket_inventory.with_lock do
ticket_roll = ticket_inventory.ticket_roll
@ticket = ticket_roll.pop
ticket_inventory.save
end
试一试,应该可以的。
3个系统用户同时点击购票
型号
class TicketInventory < ActiveRecord::Base
serialize :ticket_roll, Array
end
ticket_roll 以一系列数字作为种子
控制器
ticket_inventory = TicketInventory.find(1)
ticket_roll = ticket_inventory.ticket_roll
TicketInventory.transaction do
@ticket = ticket_roll.pop
ticket_inventory.save
end
他们都拿到了同一张票。
我考虑过 lock_version
,但这会引发错误,而不是提供下一张票。
我也查看了索引,但这需要每张票一行。
如何避免这种竞争情况?
您是否尝试使用 ActiveRecord::Locking::Pessimistic。它使用事务和数据库锁。根据文档,PostgreSQL 和 MySQL 支持它:
MySQL: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
你可以这样使用:
ticket_inventory = TicketInventory.find(1)
ticket_inventory.with_lock do
ticket_roll = ticket_inventory.ticket_roll
@ticket = ticket_roll.pop
ticket_inventory.save
end
试一试,应该可以的。