0

我正在运行一个使用 rails 3.2.3 的应用程序,它位于使用 tinyTDS 进行连接的 MS SQL Sever 实例之上。该应用程序是多线程的,使用独角兽有 4 个进程。问题是应用程序使用数据库中的一个字段来存储一个需要递增的数字,以便为每个请求分配一个唯一的帐号。当我在本地运行应用程序时没有问题,因为它不是多线程的。

当我使用 unicorn 在我们的暂存环境中运行时,当我使用多个并发请求访问应用程序时,每 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

Transaction is not what you are looking for if your issue is concurrency. 创建事务以确保某个数据库命令的正确顺序以及在发生错误时回滚它的可能性。这不是你要找的。

.with_lock应该在实例上调用。所以不是 CardValue.with_lock但是my_found_card.with_lock

还。你为什么unique id要从rails创建一个?Mysql/mariadb 可以通过自动增量主键为您轻松处理

于 2014-06-05T23:55:05.810 回答
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 回答