0

Rails 3.2.3 を使用し、tinyTDS を使用して接続する MS SQL Sever のインスタンスの上にあるアプリケーションを実行しています。アプリケーションは、ユニコーンを使用して 4 つのプロセスを持つマルチスレッド化されています。問題は、各リクエストに一意のアカウント番号を割り当てるためにインクリメントする必要がある番号を格納するために、アプリケーションがデータベース内のフィールドを使用することです。アプリケーションをローカルで実行しても、マルチスレッドではないため問題はありません。

ユニコーンを使用してステージング環境で実行しているときに、複数の同時リクエストでアプリケーションをヒットすると、10 人に 1 人程度が重複したカード番号で戻ってきます。私は以下を試しました。

レガシーコード

row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table"
next_card_number = row.value
row.value = (next_card_number.to_i + 1).to_s
row.save!
return next_card_number

レガシー コード + トランザクション

CardValue.transaction do
  row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table"
  next_card_number = row.value
  row.value = (next_card_number.to_i + 1).to_s
  row.save!
  return next_card_number
end

結果:効果なし

レガシー コード + with_lock

CardValue.with_lock do
  row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table"
  next_card_number = row.value
  row.value = (next_card_number.to_i + 1).to_s
  row.save!
  return next_card_number
end

結果: with_lock が定義されていないというエラー

レガシー コード + with_lock

CardValue.transaction do
  lock!
  row = CardValue.find_by_name("next_card_number") \ or raise "Missing next_card_number row in card_values table"
  next_card_number = row.value
  row.value = (next_card_number.to_i + 1).to_s
  row.save!
  return next_card_number
end

結果:ロックが定義されていないというエラー

4

2 に答える 2

0

Rails docs によるとwith_lock、クラスではなくインスタンスに適用されます。これは、レガシー コード + with_lock の例の代替実装です。

row = CardValue.find_by_name("next_card_number") or raise "Missing next_card_number row in card_values table"
row.with_lock do
  next_card_number = row.value
  row.value = (next_card_number.to_i + 1).to_s
  row.save!
  return next_card_number
end
于 2014-06-09T17:47:00.027 に答える
0

Transaction is not what you are looking for if your issue is concurrency. トランザクションは、特定のデータベース コマンドの適切な順序を保証し、エラーが発生した場合にロールバックできるようにするために作成されます。これはあなたが探しているものではありません。

.with_lockインスタンスで呼び出す必要があります。そうではありません CardValue.with_lockmy_found_card.with_lock

また。なぜunique idレールから作成するのですか?Mysql/mariadb は、自動インクリメント主キーを使用して簡単に処理できます

于 2014-06-05T23:55:05.810 に答える