在Squeryl中设置事务隔离级别

3
如何使用Squeryl设置事务隔离级别?
例如,我现在正在使用Postgresql,并需要针对特定的单个事务使用可串行化隔离。我同时使用纯Squeryl和带有Lift Web框架的Squeryl-Record。
当然,其他人可能需要为其他数据库设置不同的隔离级别,而不是针对单个事务,而是整个会话,因此通用答案更可取。
更新:
最终,我采用了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: Cannot change transaction isolation level in the middle of a transaction.
只要我使用transaction{}而不是inTransaction{},立即回滚应该不会有害。
隔离级别应在transaction{}提交或回滚之后但在连接返回到连接池之前重置。 我不确定如何完成这一点。 但在我的情况下,c3p0连接池似乎会重置隔离级别,并且每个transaction{}都以默认隔离级别启动,即使我从未自己清理过它们。
我不太满意的是当发生冲突时的异常。 我想特别捕获这样的异常并重试事务。 但它只是一个通用的运行时异常:
java.lang.RuntimeException: Exception while executing statement : ERROR: could not serialize access due to concurrent update 它包装了另一个不幸也很通用的异常(org.postgresql.util.PSQLException)。
虽然不完美,但它可以胜任,直到Squeryl希望得到事务隔离支持。 我正在使用上面的代码与Squeryl 0.9.4。
2个回答

3

现在这个过程有些手动化。如果您需要为整个会话设置适当的级别,那么您可以在Session工厂中设置相应的级别。

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) 我还没有尝试编译上述内容,所以可能会有语法错误。无论如何,我认为它会给你一个大致的想法。


我还没有机会尝试这个。但它绝对看起来是正确的方法。谢谢! - Dr.Haribo

1
关于异常:org.postgresql.util.PSQLException 扩展了 java.sql.SQLException,该类具有 getSQLState() 方法。像这样由序列化失败引起的异常将从此方法返回"40001"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接