Rails postgresql如何将事务隔离级别设置为可序列化

时间:2011-10-27 11:27:11

标签: ruby-on-rails postgresql transactions callback

我有一个评论模型,属于一个主题模型。在Comment模型中,我有一个before_create回调

def on_create
  Topic.transaction(:require_new => true) do
    Topic.connection.execute('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE')
    self.topic.increment!(:comment_counter) if conditions
  end
end

问题是我得到ActiveRecord::StatementInvalid: PGError: ERROR: SET TRANSACTION ISOLATION LEVEL must be called before any query

是否有另一种设置事务隔离级别的方法?

3 个答案:

答案 0 :(得分:7)

PostgreSQL要求在事务开始之后和任何DML(SELECT,INSERT,DELETE等)语句之前执行SET TRANSACTION语句。从文档中看,所有这些东西都必须通过连接对象而不是事务对象来完成。像(未经测试的)

之类的东西
Topic.connection.begin_db_transaction
  Topic.connection.execute('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE')
  # Other things go here. I'd test with another literal SQL statement to make
  # sure it works like I'd hope it does. Then possibly try rewriting in Rails.
Topic.connection.commit_db_transaction

真的希望我错了。

一个令人反感的替代方法是更改​​PostgreSQL服务器上所有事务的默认隔离级别。 (搜索http://www.postgresql.org/docs/current/static/runtime-config-client.html以获取“default_transaction_isolation”。)但这感觉就像使用大炮杀死苍蝇一样。

答案 1 :(得分:7)

从Rails 4开始,#transaction provides an :isolation option

  

如果您的数据库支持为事务设置隔离级别,您可以这样设置:

Post.transaction(isolation: :serializable) do
  # ...
end

答案 2 :(得分:4)

您可能会发现transaction_isolation gem有用:https://github.com/qertoip/transaction_isolation