我需要在这里进行交易还是只需要一个锁就可以了?

问题描述 投票:0回答:1

我有这张桌子:

create_table :api_usages do |t|
  t.references :api_key, null: false, foreign_key: true 
  t.date :billing_date, null: false 
  t.integer :request_count, null: false 
  t.timestamps 
end

发出 API 请求时,我想增加(如果是新行则设置为 1)具有匹配

api_key
billing_date
的行。如果用户快速连续发出两个 API 请求,我想确保不存在竞争条件。

这足够了吗?

api_usage = ApiUsage.lock.find_or_initialize_by(api_key_id: api_key_id, billing_date: billing_date)
api_usage.request_count ||= 0
api_usage.request_count += 1
api_usage.save!
# The lock is released after save! completes, as part of the implicit transaction's lifecycle.

或者我应该打包交易吗?

ApiUsage.transaction do
  api_usage = ApiUsage.lock.find_or_initialize_by(api_key_id: api_key_id, billing_date: billing_date)
  api_usage.request_count ||= 0
  api_usage.request_count += 1
  api_usage.save!
  # The lock is held until the end of the transaction block.
end
# The lock is released after the transaction block completes.
ruby-on-rails activerecord transactions locking
1个回答
0
投票

这是我尝试通过更新插入来解决这个问题,没有锁或事务:

ApiUsage.upsert(
  { 
    api_key_id: api_key_id, billing_date: billing_date, request_count: 1, 
    created_at: Time.current, updated_at: Time.current },
    unique_by: { columns: %i[api_key_id billing_date] },
    on_duplicate: Arel.sql('request_count = api_usages.request_count + 1, updated_at = EXCLUDED.updated_at')
  }
)
© www.soinside.com 2019 - 2024. All rights reserved.