如何使用 Squeryl 设置事务隔离级别?
例如,现在我正在使用 Postgresql,并且需要对特定的单个事务进行可序列化的隔离。我将普通的 Squeryl 和 Squeryl-Record 与 Lift Web 框架一起使用。
其他人当然可能需要针对整个会话(而不是单个事务)的其他数据库的其他隔离级别,所以一般的答案是可取的。
更新:
我最终得到了 Dave Whittaker 代码的修改版本:
def transactionWith[T](isolation: Int)(block: => T): T =
transaction {
val connection = Session.currentSession.connection
connection.rollback // isolation cannot be changed in the middle of a tx
connection.setTransactionIsolation(isolation)
block
}
问题是,如果事务已经启动,则无法更改隔离级别。对我来说就是这种情况,如果没有回滚,我会得到:
org.postgresql.util.PSQLException:无法在事务中间更改事务隔离级别。
只要我使用 transaction{} 而不是 inTransaction{},我认为立即回滚应该没有害处。
隔离级别应在事务提交或回滚后重置,但在连接返回到连接池之前。我不确定如何做到这一点。但在我的情况下,c3p0 连接池似乎重置了隔离级别,并且每个事务{}都以默认隔离级别开始,即使我自己从未清理过它们。
我不太满意的是发生冲突时的例外情况。我想专门捕获这样的异常并重试事务。但这只是一个通用的运行时异常:
java.lang.RuntimeException:执行语句时出现异常:错误:由于并发更新而无法序列化访问
它包装了另一个异常,不幸的是它也是通用的(org.postgresql.util.PSQLException)。
不完美,但在 Squeryl 希望获得对事务隔离的支持之前,它可以完成这项工作。我将上述代码与 Squeryl 0.9.4 一起使用。