ruby-on-rails - 处理事务内的唯一约束异常

标签 ruby-on-rails ruby postgresql

我有两个 Rails 模型/表,我想将它们作为事务的一部分插入。

例如,以下是我的表格:

  • 帖子:(id)
  • 评论:(id、post_id、comment_text、user_id)
  • 评论者:(id, post_id, user_id),对 (post_id, user_id)

现在我正在尝试大约相当于:

ActiveRecord::Base.transaction do
  Comment.create!(post: post, user: user, comment_text: '...')

  begin
    Commenters.find_or_create_by!(post: post, user: user)
  rescue PG::UniqueViolation
  end
end

这在 99.9% 的情况下有效,但有时两个并发评论会触发 PG::UniqueViolation。

即使我捕获并抑制了 PG::UniqueViolation,整个事务也会失败,原因是:

错误:当前事务被中止,命令被忽略,直到事务 block 结束

我意识到我已经可以通过加入帖子和评论表来实现这一点,但这是一个简化的示例。

是否有一种更简单的方法来确保两次插入都作为事务的一部分发生,同时仍然忽略唯一的违规,因为我们可以假设记录已经存在?

最佳答案

事务内引发的异常会做两件事:

  1. 回滚事务,以便事务内所做的任何更改都不会保留在数据库中。
  2. 异常在事务 block 之外传播。

因此,您可以将异常处理程序移至 transaction 调用之外:

begin
  ActiveRecord::Base.transaction do
    Comment.create!(post: post, user: user, comment_text: '...')
    Commenters.find_or_create_by!(post: post, user: user)
  end
rescue PG::UniqueViolation
  retry
end

如果您想要更安全,您可以添加一个计数器,仅重试几次。

关于ruby-on-rails - 处理事务内的唯一约束异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51035129/

相关文章:

ruby-on-rails - 我的 Ruby on Rails 应用程序如何在没有密码的情况下访问数据库?

database - 根据一行中的更改更新多行

ruby-on-rails - ActionView::MissingTemplate:缺少模板

ruby-on-rails - 哪种编程语言最适合我的需求?

ruby - 在这种情况下,正则表达式比数组比较快吗?

ruby-on-rails - 将 header 添加到 get_response 方法

python - 如何在 Django 过滤器中做小于或等于和大于等于?

ruby-on-rails - 为什么 Rake 任务中的这个 Ruby 脚本不能选择 Rails 环境?

ruby-on-rails - 无法安装 gem 'pg' 将rails应用程序部署到heroku

ruby - rake 中止!语法错误,意外的 tLSHFT