所以我的模型对象上有一个方法,当行中的二进制字段从null更新为true时,该方法会创建一个唯一的序列号。它实现如下:
class AnswerHeader < ApplicationRecord
before_save :update_survey_complete_sequence, if: :survey_complete_changed?
def update_survey_complete_sequence
maxval =AnswerHeader.maximum('survey_complete_sequence')
self.survey_complete_sequence=maxval+1
end
end
我的问题是我需要锁定什么才能同时更新两行,而不是两行具有相同的survey_complete_sequence?
如果可以锁定单行而不是整个表,那么这是一个很好的,因为这是用户经常访问的表。
答案 0 :(得分:1)
如果您正在使用postgress,也许Sequenced可以帮助您而无需在数据库级别定义序列。
Survey_complete_sequence应该是增量的吗?如果没有,也许随机化一个bigint?
答案 1 :(得分:1)
如果你想在应用程序逻辑本身处理它,而不是让数据库处理这个。您可以使用rails with_lock函数来创建事务并在所选行上获取行级数据库锁(在您的情况下为单行)。
答案 2 :(得分:1)
您可能不想锁定该表,即使您锁定了当前正在更新该行的行,您的maxval将基于另一个更新来读取和生成序列#。
除非你有一个巨大的表格,并且每毫秒都有很多更新(大约数千),否则这在现实生活中不应成为问题。但是如果这个想法困扰你,你可以继续在表格上添加一个独特的索引,在&#34; survey_complete_sequence&#34;柱。数据库错误将传播到您可以在应用程序中处理的Rails异常。
答案 3 :(得分:1)
我相信你应该给一些咨询锁。它确保同一个代码块不会同时在两台机器上执行,同时仍然保持该表对其他业务开放。
它使用数据库,但它不会锁定你的表。
您可以像这样使用名为“with_advisory_lock”的gem:
$model->value = isset( $value ) ? $value : null;
https://github.com/ClosureTree/with_advisory_lock
它不适用于SQLite。
答案 4 :(得分:1)
您需要锁定的内容
在您的情况下,您必须锁定包含最大survey_complete_sequence
的行,因为这是每个查询在获取您需要的值时将查找的行。
maxval =AnswerHeader.maximum('survey_complete_sequence')
是否可以锁定单行而不是整个表格
您的方案没有此类特定锁定。但是你可以使用Postgresql SELECT FOR UPDATE
row-level locking。
在实际上获取行上的独占行级锁定 修改行,使用SELECT FOR UPDATE选择行。
你可以在rails中使用pessimistic locking并指定你将使用哪个锁。
调用锁定(&#39;某些锁定子句&#39;)以使用特定于数据库的锁定 你自己的条款,如锁定模式&#39;或者&#39;更新NOWAIT&#39;
以下是如何从rails官方指南本身实现这一目标的一个例子
Item.transaction do
i = Item.lock("LOCK IN SHARE MODE").find(1)
...
end
使用锁的关系通常包含在事务中以防止死锁条件。
所以你需要做的是 -
SELECT FOR UPDATE
锁定应用于包含maximum('survey_complete_sequence')
AnswerHeader