2011-11-25 153 views
3

如何使用Squeryl設置事務隔離級別?在Squeryl中設置事務隔離級別

例如,現在我正在使用Postgresql,並且需要特定單個事務的可序列化隔離。我使用普通的Squeryl和Squeryl-Record和Lift web框架。

其他可能當然需要其他數據庫的整個會話(而不是單個事務)的其他隔離級別,所以一般的答案是可取的。

更新:

我結束了的戴夫·惠特克的代碼,這個修改後的版本:

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.

只要我使用的交易{},而不是在inTransaction {}我覺得做一個即時回滾應該沒有壞處。

在事務{}提交或回滾之後,但在將連接返回到連接池之前,應該重置隔離級別。我不知道如何做到這一點。但在我的情況下,c3p0連接池似乎重置了隔離級別,並且每個事務都以默認隔離級別開始,即使我從不自己清理它們。

我不那麼滿意的事情是有衝突時的例外。我想特別注意這樣一個例外,然後重試交易。但它只是一個通用的運行時異常:

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上使用上面的代碼。

回答

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)(......) 
} 

我認爲這會工作,但一)我m不能完全確定什麼時候應該設置隔離級別,我假設在執行任何其他語句之前將其設置在當前事務中將起作用,並且b)我沒有試圖編譯上述內容,因此可能存在語法錯誤。無論如何,我認爲它會給你一個大概的想法。

+0

我還沒有機會嘗試這個呢。但它絕對看起來像要走的路。謝謝! –

1

關於例外:org.postgresql.util.PSQLException延伸java.sql.SQLException,它有一個getSQLState()方法。由此類序列化失敗引起的異常將從此方法返回"40001"