我有一个评论模型,属于一个主题模型。在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
。
是否有另一种设置事务隔离级别的方法?
答案 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