web-dev-qa-db-ja.com

1つのHibernateセッション内で複数のトランザクションを使用できますか?

1つのHibernateセッション内で複数のトランザクションを使用できますか?

これが望ましいものかどうかはわかりません。私のコードでは、実行中のスレッドが長く、キューにあるものに応じてアイテムをブロックキューから取得し、休止状態オブジェクトを作成して保存する必要がある場合や、何もする必要がない場合があります。

各アイテムは個別であるため、アイテム1が保存され、アイテム2が保存されない場合、アイテム1がデータベースに追加されないようにしたい理由はありません。

そのため、これを行う最も簡単な方法は、新しいセッションを作成し、トランザクションを開き、新しいオブジェクトを保存し、トランザクションをコミットし、セッションを閉じるために作成する必要がある各アイテムです

ただし、それは各セッションごとに新しいセッションが作成されることを意味します。これは、Hibernate独自の推奨事項に反するようで、リクエストごとのセッションを実行しません。したがって、私の代替案は、スレッド内に1つのセッションを作成し、必要に応じて新しいオブジェクトを作成するために必要に応じて新しいトランザクションを開いてコミットすることでした。しかし、このアプローチの例は見たことがなく、実際に機能するかどうかはわかりません。

24
Paul Taylor

セッションごとのセッションパターンは、ローカルトランザクションを実行する場合、セッションごとに1つのJDBC接続を使用します。 JTAの場合、接続は各ステートメントの後に積極的に解放され、次のステートメントでのみ再取得されます。

HibernateトランザクションAPIは、ローカルトランザクションの場合はJDBC接続に、JTAの場合は関連するUserTransactionにbegin/commit/rollbackを委任します 。したがって、同じHibernateセッションで複数のトランザクションを実行できますが、キャッチがあります。例外がスローされると、そのセッションを再利用できなくなります。

私のアドバイスは、分割統治することです。すべてのアイテムを分割し、それらのそれぞれに対してCommandオブジェクトを構築し、それらを _ExecutorService#invokeAll_ に送信します。返されたリストを使用して繰り返し処理し、 Future#get() を呼び出して、すべてのバッチジョブが完了するまで元のスレッドが待機するようにします。

ExecutorServiceは、すべてのコマンドを同時に実行し、各コマンドが独自の_@Transaction_を使用するサービスを使用するようにします。トランザクションはスレッドにバインドされているため、すべての バッチジョブが単独で実行されます になります。

29
Vlad Mihalcea

もちろん、できます。ハイバネートセッションは、多かれ少なかれデータベース接続であり、データベースオブジェクトのキャッシュです。また、単一のデータベース接続で複数の連続したトランザクションを持つことができます。さらに、接続プールを使用すると、接続は閉じられず、リサイクルされます。

すべきかどうかは、セッションからオブジェクトを再利用することです。チャンスはあるが、前のトランザクションがセッションに入れたオブジェクトを再利用できる場合は、複数のトランザクションに対して1つのセッションを維持する必要があります。しかし、一度オブジェクトがコミットされたら、それは決して再利用されません。セッションを閉じて新しいセッションを再び開くか、単にそれをクリアする方が確かに良いです。

どうやってするの :

Sessionオブジェクトがある場合、以下を使用してトランザクションを作成します。

Transaction transaction;
transaction = session.beginTransaction();
... (operations in the context of transaction)
transaction.commit();
... (other commands outside of any transaction)
transaction = session.beginTransaction();
... (and so on and so forth ...)
12
Serge Ballesta

Hibernatesドキュメントから

「セッションは、1回使用してから破棄する必要がある安価な非スレッドセーフオブジェクトです。単一の要求、会話、または単一の作業単位です。セッションは、JDBC接続またはデータソースを取得しません。使用するまでリソースを消費しません。」

そのため、セッションを何度も作成する場合、システムに大きな負荷はかかりません。セッションが長すぎると、セッションがスレッドセーフではないため問題が発生する可能性があります。私の意見では、最も簡単な解決策が最善です。「これを行う最も簡単な方法は、セッション、トランザクションを開く、新しいオブジェクトを保存する、トランザクションをコミットする、セッションを閉じる」

ちなみに、単一のレコードを作成している場合、トランザクションはあまり必要ありません。単一のレコードを作成することは、トランザクションを使用する本質的に「すべてまたはなし」のことです

3
faisalbhagat
package hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
class Tester {
public static void main(String[] args) {
    SessionFactory sf = new org.hibernate.cfg.Configuration().configure().buildSessionFactory(new StandardServiceRegistryBuilder().configure().build());
    Session session = sf.openSession();
    session.beginTransaction();
        Student student = new Student();
    student.setName("Mohammad Faizan");
    student.setRollNo(1309114040);
        session.save(student);
    session.getTransaction().commit();
    session.getTransaction().begin();
    session.load(Student.class,23);
    student.setName("New Name");
    student.setRollNo(123);
    session.update(student);
    session.getTransaction().commit();
    session.close();
  }
}
0
Faizan Mohammad

短い答えはイエスです。トランザクションに同じセッションを使用できます。 org.hibernate.Transactionを見てください。トランザクションを管理するためのメソッドが必要です。

0
Vinay