在Squeryl中设置事务隔离级别

时间:2011-11-25 18:08:42

标签: database scala transactions isolation-level squeryl

如何使用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:无法在事务中间更改事务隔离级别。

只要我使用事务{}而非inTransaction {}我认为立即回滚应该没有坏处。

隔离级别应在事务{}提交或回滚后重置,但在连接返回到连接池之前。我不知道如何做到这一点。但在我的情况下,c3p0连接池似乎重置了隔离级别,并且每个事务{}都以默认隔离级别开始,即使我从未自己清理它们。

我不满意的是发生冲突时的例外情况。我想特别捕获这样的异常并重试该事务。但它只是一个通用的运行时异常:

  

java.lang.RuntimeException:执行语句时出现异常:ERROR:由于并发更新而无法序列化访问

它包装了另一个异常,遗憾的是它也是通用的(org.postgresql.util.PSQLException)。

并不完美,但在Squeryl希望获得对事务隔离的支持之前,它才能完成任务。我使用上面的代码与Squeryl 0.9.4。

2 个答案:

答案 0 :(得分:3)

现在这将是一个有点手动的过程。如果您需要整个会话,那么我想您可以在SessionFactory中设置适当的级别,即。

SessionFactory.concreteFactory = Some(()=> {
  val connection = java.sql.DriverManager.getConnection("...")
  connection.setTransactionIsolation(...)
  Session.create(connection, new PostgreSqlAdapter)
 })

对于单笔交易,这会有点困难。您可以使用Session.currentSession或Session.currentSessionOption访问当前会话,并且必须在事务发生之前设置隔离级别,然后再将其设置回来。当然,创建自己的功能并不是很难:

def transactionWith(isolation: Int)(block: => T): T = {
  trasaction{
    val connection = Session.currentSession.connection
    val oldIsolation = connection.getTransactionIsolation()
    connection.setTransactionIsolation(isolation)
    try {
      block
    } finally {
      connection.setTransactionIsolation(oldIsolation)
    }
  }
}

然后你会像

一样使用它
transactionWith(Connection.TRANSACTION_SERIALIZABLE){
   from(blablabla)(......)
}

我认为这样可行但是a)我不完全确定何时应该设置隔离级别,我假设在执行任何其他语句之前在当前事务中设置它将起作用并且b)我还没有尝试编译以上内容,因此可能存在语法错误。无论如何,我认为它会给你一般的想法。

答案 1 :(得分:1)

关于例外:org.postgresql.util.PSQLException扩展java.sql.SQLException,其中getSQLState()方法。像这样的序列化失败导致的异常将从此方法返回"40001"

相关问题