Rails 7 + MariaDB:为belongs_to关联列添加缺失唯一性约束
Rails 7 + MariaDB 为Cancellation关联添加唯一约束操作方案
全程操作不会丢失合法存量数据,也不会破坏已有的外键约束,按顺序执行即可:
- 第一步:清理存量重复数据
加唯一索引的前提是表内不存在重复的subscription_id值,先进入Rails控制台执行查询定位重复记录:
按照自身业务规则处理这些重复数据,比如保留最早创建的Cancellation记录,其余冗余记录做删除或归档处理。处理完成后重新执行上述查询,确认返回空数组再进行下一步。# 查询所有关联了多条Cancellation的Subscription ID duplicate_sub_ids = Cancellation.group(:subscription_id).having("COUNT(*) > 1").pluck(:subscription_id) - 第二步:执行数据库迁移替换索引
先生成迁移文件:
编辑生成的迁移文件,用原生SQL原子完成旧普通索引删除、新唯一索引添加的操作,避免中间窗口期出现外键无索引的问题,也不会破坏已存在的外键约束:rails generate migration AddUniqueIndexToCancellationsOnSubscription
确认代码无误后执行迁移:class AddUniqueIndexToCancellationsOnSubscription < ActiveRecord::Migration[7.0] def up execute <<~SQL ALTER TABLE cancellations DROP INDEX index_cancellations_on_subscription_id, ADD UNIQUE INDEX index_cancellations_on_subscription_id (subscription_id); SQL end def down execute <<~SQL ALTER TABLE cancellations DROP INDEX index_cancellations_on_subscription_id, ADD INDEX index_cancellations_on_subscription_id (subscription_id); SQL end endrails db:migrate - 第三步:补充模型层校验
数据库层唯一索引是兜底防重复的最后防线,同时需要在模型层加校验,提前拦截非法写入,避免直接抛出数据库异常:
编辑app/models/cancellation.rb文件:class Cancellation < ApplicationRecord belongs_to :subscription # 新增subscription_id唯一性校验 validates :subscription_id, uniqueness: true end
注意:如果存在高并发写入Cancellation的场景,模型层校验存在竞态条件漏判的可能,数据库层的唯一索引绝对不能省略。
内容的提问来源于stack exchange,提问作者Kalsan
相关产品推荐
相关产品推荐

