3

Squerylを使用してトランザクション分離レベルを設定するにはどうすればよいですか?

たとえば、現在私はPostgresqlを使用しており、特定の単一トランザクションに対してシリアル化可能な分離が必要です。私はLiftWebフレームワークでプレーンなSquerylとSqueryl-Recordの両方を使用しています。

もちろん、他のデータベースでは(単一のトランザクションではなく)セッション全体で他の分離レベルが必要になる場合があるため、一般的な回答が望ましいです。

アップデート:

私はDaveWhittakerのコードのこの修正バージョンに行き着きました:

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 {}ではなくtransaction{}を使用している限り、すぐにロールバックを実行しても害はないと思います。

分離レベルは、transaction {}がコミットまたはロールバックした後、接続が接続プールに戻る前にリセットする必要があります。それを達成する方法がわかりません。しかし、私の場合、c3p0接続プールは分離レベルをリセットしているようで、自分でクリーンアップしなくても、すべてのトランザクション{}はデフォルトの分離レベルで開始されます。

私があまり満足していないのは、対立がある場合の例外です。特にそのような例外をキャッチして、トランザクションを再試行したいと思います。しかし、これは単なる一般的なランタイム例外です。

java.lang.RuntimeException:ステートメントの実行中に例外が発生しました:エラー:同時更新のため、アクセスをシリアル化できませんでした

残念ながら一般的な別の例外(org.postgresql.util.PSQLException)をラップします。

完璧ではありませんが、Squerylがトランザクション分離のサポートを取得するまでは機能します。上記のコードをSqueryl0.9.4で使用しています。

4

2 に答える 2

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)試していません。上記をコンパイルして、構文エラーが発生する可能性があります。とにかく、それはあなたに一般的な考えを与えると思います。

于 2011-11-25T23:03:28.967 に答える
1

例外について:メソッドを持つorg.postgresql.util.PSQLExceptionextends 。このようなシリアル化の失敗によって引き起こされた例外は、このメソッドから返されます。java.sql.SQLExceptiongetSQLState()"40001"

于 2012-04-03T23:43:50.283 に答える