2016-11-01 5 views
-1

私はトランザクション内の複数のエンティティを削除するための雄弁な方法を探しています。ロールバックによるHQL一括処理による削除

idsのリストが与えられた場合、影響を受ける行の数がリストの数と異なる場合、例外をスローしたいと思います。現在、私は以下のスニペットを使用しますが、それは定型の多くが含まれます:

private int deleteMyEntities(final List<Integer> ids) { 
    final Session session = SomeHelper.getOpenSession(); 
    Transaction tx = null; 
    try { 
     tx = session.beginTransaction(); 
     final int affectedCount = session.createQuery("delete MyEntity where id in (:ids)") 
      .setParameterList("ids", ids) 
      .executeUpdate(); 
     if (affectedCount == ids.size()) { 
     tx.commit(); 
     tx = null; 
     return affectedCount; 
     } else { 
     throw new HibernateException("Delete count does not match target count."); 
     } 
    } finally { 
     if (tx != null) { 
     tx.rollback(); 
     } 
    } 
    } 

いくつかの落とし穴:

  • これは、依存性注入、注釈駆動型取引やその他の細かな点を欠いたレガシーアプリです。 「春使用」に似た答えは例外的に有用ではありません。
  • Java 1.6にコンパイルします。
+0

でフィルターにオープンし、要求(ビュー内のオープンセッション)の期間中に開催され、これセッションリセットされますか? – developer

+0

定型文のトンがあります。 – Andreas

+0

MyEntityオブジェクトの代わりにIDフィールドが –

答えて

1

私はそれを刺しました。この具体的なケースでは、tryステートメントでトランザクションを開始する必要はありません。開始できない場合はロールバックできない可能性がありますが、もし可能であっても、まだ何もしていない。トランザクションがオープンできなかった場合、クローズするものはありません。つまり、接続プールから孤立したスレッドはありません。

private int deleteMyEntities(final List<Integer> ids) { 
    final Session session = SomeHelper.getOpenSession(); 
    Transaction tx = session.beginTransaction(); 
    try { 
    final int affectedCount = session.createQuery("delete MyEntity where id in (:ids)") 
     .setParameterList("ids", ids) 
     .executeUpdate(); 
    if (affectedCount == ids.size()) { 
     tx.commit(); 
     return affectedCount; 
    } else { 
     throw new HibernateException("Delete count does not match target count."); 
    } 
    } catch (Exception e) { 
    tx.rollback(); 
    throw e; 
    } 
} 

残念ながら、アノテーションベースのトランザクションのような独自のカスタムフレームワークを作成することなく「いい」とすることは難しいでしょう。あなたがAOPライブラリにアクセスすることができれば、そのことを疑問に思うあなたの説明に基づいてたくさん隠すのにそれを使うことができます。

+0

のDTOを作成するこの方法では、メソッドの署名は 'public int deleteMyEntities(final List ids)例外 'をスローする必要があります。 '例外をスローする'は、不快ではないと言っても過言ではない。 – Andreas

+0

メソッドシグネチャの変更を排除する新しいRuntimeException(e)をスローするようなRuntimeExceptionで「e」をラップすることはできますが、最も洗練された解決策ではありません。 –

0

私が解決策を見つけたのは、アレックスの提案に含まれていました。私はコードを少しDRYerに保つために多くのロジックを引き出しました。注:Hibernateセッションは、このコードの問題が何であるかをrecoverFromFailedTransaction

public int deleteMyEntity(final List<Integer> ids) { 
    return deleteEntities("MyEntity", ids); 
    } 

    private int deleteEntities(final String entityName, final List<Integer> ids) { 
    final Session session = SomeHelper.getOpenSession(); 
    final Query query = session.createQuery("delete " + entityName + " where id in (:ids)") 
     .setParameterList("ids", ids); 
    return performBatchOperation(query, ids.size()); 
    } 

    private int performBatchOperation(final Query query, final int expectedAffectedCount) { 
    final Session session = SomeHelper.getOpenSession(); 
    final Transaction tx = session.beginTransaction(); 
    try { 
     final int affectedCount = query.executeUpdate(); 
     if (affectedCount == expectedAffectedCount) { 
     tx.commit(); 
     return affectedCount; 
     } else { 
     throw new HibernateException(String.format(
      "Affected count [%d] does not match expected count [%d].", 
      affectedCount, 
      expectedAffectedCount)); 
     } 
    } catch (RuntimeException e) { 
     logger.error(e); 
     recoverFromFailedTransaction(tx); 
     throw e; 
    } 
    } 

private void recoverFromFailedTransaction(final Transaction tx) { 
    try { 
     if (tx != null) { 
     tx.rollback(); 
     } 
    } catch (HibernateException e) { 
     logger.error("Exception when rolling back failed transaction. ", e); 
    } 
    try { 
     SomeHelper.getOpenSession().close(); 
    } catch (HibernateException e) { 
     logger.error("Exception when closing session . ", e); 
    } 
    SomeHelper.resetOpenSession(); 
    logger.warn("Session discarded."); 
    } 
関連する問題