我在Rails中有一个Transaction模型,代表将要从信用卡中扣除的财务交易。
当创建一个交易时,它的状态为:new
。当我尝试结算费用(这将在DelayedJob中发生)时,我会将状态更新为:pending
。如果状态不是:new
,则会忽略任何后续对charge
的调用。
幼稚版(不考虑并发):
# Trigger a card to be charged
def charge_transaction
return unless status == :new
self.transaction do
self.delay.settle_credit_card
self.update_attribute(:status, :pending)
end
end
# Actually do the charging (in a delayed worker)
def settle_credit_card
# ... Interact with our payment gateway
end
由于这是一个负载均衡的Web应用程序,我希望确保我们考虑到并发,并且不会创建重复的收费(由于并发请求)。 我了解乐观锁定的好处,但在这种情况下,我不介意拥有此关键区域,因为同时尝试收费(或以任何方式更新交易)应该是异常情况。
以下是使用悲观行级锁定的尝试
并发版本(选项1)
# Trigger a card to be charged
def charge_transaction
# Obtain row-lock
self.with_lock do
self.reload # Reload once lock is obtained - necessary?
# Check status after lock/reload
return unless status == :new
self.delay.settle_credit_card
self.update_attribute(:status, :pending)
end
end
并发版本(选项2)
# Trigger a card to be charged
def charge_transaction
# Begin transaction without lock
self.transaction do
self.reload(lock: true) # Reload and obtain lock
# Check status after lock/reload
return unless status == :new
self.delay.settle_credit_card
self.update_attribute(:status, :pending)
end
end
以下哪种方法是有效的(或两种都有效)? 在获得锁之后是否需要显式重新加载(以确保事务对象是当前的),还是当获得锁时Rails会自动执行? 如果两种方法都有效,哪种更可取?
非常感谢!