我的数据库中有帖子和组织。帖子属于组织和组织has_many帖子。
我的帖子表中有一个现有的post_id列,我现在在创建新帖子时手动递增。 如何将自动增量添加到作用于organisation_id的列?
目前我使用mysql作为我的数据库,但我打算切换到PostgreSQL,因此如果可能,解决方案应该适用于两者:)
非常感谢!
答案 0 :(得分:5)
@ richard-huxton有正确的答案并且是线程安全的。
使用事务块并在该事务块内使用SELECT FOR UPDATE。这是我的rails实现。在ruby类上使用'transaction'来启动事务块。在要锁定的行上使用“lock”,实质上阻止对该行的所有其他并发访问,这是确保唯一序列号所需的。
class OrderFactory
def self.create_with_seq(order_attributes)
order_attributes.symbolize_keys!
raise "merchant_id required" unless order_attributes.has_key?(:merchant_id)
merchant_id = order_attributes[:merchant_id]
SequentialNumber.transaction do
seq = SequentialNumber.lock.where(merchant_id: merchant_id, type: 'SequentialNumberOrder').first
seq.number += 1
seq.save!
order_attributes[:sb_order_seq] = seq.number
Order.create(order_attributes)
end
end
end
我们为后台工作运行sidekiq,因此我通过创建1000个后台作业来测试此方法,以使用8个工作程序创建订单,每个工作程序具有8个线程。如果没有锁定或事务块,则会按预期发生重复序列号。使用锁和事务块,所有序列号看起来都是唯一的。
答案 1 :(得分:4)
首先,创建一个表org_max_post (org_id, post_id)
。添加新组织时填充它(我使用数据库触发器)。
然后,在添加新帖子时,您需要:
BEGIN
交易SELECT FOR UPDATE
该组织要锁定它的行post_id
递增1,更新行。COMMIT
用于完成更新和释放锁定的事务。您希望所有这一切在一个事务中发生,当然,并锁定org_max_post中的相关行。您希望确保将新的post_id分配给一个且仅一个帖子,并且如果帖子未能提交,则您不会浪费post_id。
如果您希望变得聪明并减少应用程序代码中的SQL,您可以执行以下操作之一:
删除帖子显然不会影响您的org_max_post
表格,因此不会破坏您的编号。
使用触发器阻止对数据库级别的帖子进行任何更新。检查OLD与NEW post_id
中的任何更改,如果有,则抛出异常。
然后删除posts表中现有的冗余id列,并使用(org_id,post_id)作为主键。如果你遇到这个麻烦,你也可以把它当作你的pkey使用。
哦 - post_num
或post_index
可能比post_id
好,因为它不是标识符。
我不知道有多少这样可以很好地使用rails我担心 - 上次我看到它时,数据库处理是荒谬的原始。
答案 2 :(得分:0)
首先,我必须说这不是一个好习惯,但我只关注你的问题的解决方案: 您可以通过PostsController进行组织的帖子计数:
def create
post = Post.new(...)
...
post.post_id = Organization.find(organization_id).posts.count + 1
post.save
...
end
您不应该自己更改数据库。让ActiveRecord来处理它。
答案 3 :(得分:0)
很高兴知道如何实现它。我更喜欢自己使用宝石。