Database 在Squiryl中设置事务隔离级别
如何使用Squeryl设置事务隔离级别 例如,现在我正在使用Postgresql,需要对特定的单个事务进行序列化隔离。我在Lift web框架中使用了普通的Squeryl和Squeryl记录 当然,对于整个会话(而不是单个事务),其他数据库可能需要其他隔离级别,因此一般答案更可取 更新: 我最终得到了Dave Whittaker代码的修改版本:Database 在Squiryl中设置事务隔离级别,database,scala,transactions,isolation-level,squeryl,Database,Scala,Transactions,Isolation Level,Squeryl,如何使用Squeryl设置事务隔离级别 例如,现在我正在使用Postgresql,需要对特定的单个事务进行序列化隔离。我在Lift web框架中使用了普通的Squeryl和Squeryl记录 当然,对于整个会话(而不是单个事务),其他数据库可能需要其他隔离级别,因此一般答案更可取 更新: 我最终得到了Dave Whittaker代码的修改版本: def transactionWith[T](isolation: Int)(block: => T): T = transaction {
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
}
问题是,如果事务已经启动,就不能更改隔离级别。我就是这样,如果没有回滚,我会得到:
Or.PrgRESQL.UTI.PSQLExExc:不能在事务中间更改事务隔离级别。< /P> 只要我使用的是事务{}而不是内部事务{},我认为立即回滚应该没有什么坏处
隔离级别应该在事务{}提交或回滚之后,但在连接返回到连接池之前重置。我不知道如何做到这一点。但在我的例子中,c3p0连接池似乎重置了隔离级别,并且每个事务{}都以默认隔离级别开始,即使我自己从未清理它们 我不太高兴的是,当发生冲突时,有一个例外。我想专门捕获这样一个异常并重试该事务。但这只是一个通用的运行时异常: java.lang.RuntimeException:执行语句时异常:错误:由于并发更新,无法序列化访问 它包装了另一个异常(org.postgresql.util.PSQLException),不幸的是它也是通用的虽然不是完美的,但在Squeryl有望获得事务隔离支持之前,它可以完成这项工作。我将上面的代码用于Squiryl 0.9.4。现在这将是一个手动过程。如果您在整个会话中都需要它,那么我想您可以简单地在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)我没有尝试编译上述内容,因此可能存在语法错误。无论如何,我想它会给你一个大致的想法。关于异常:
org.postgresql.util.PSQLException
扩展了java.sql.SQLException
,它有一个getSQLState()
方法。像这样的序列化失败导致的异常将从此方法返回“40001”
。我还没有机会尝试此方法。但这看起来确实是一条路要走。非常感谢。