最近、Hibernateのバージョンを4.3.4.Finalにアップグレードしました。 Hibernateのコンテキストセッション構成に基づくと、この新しいバージョンはThreadLocalに基づくものではなくなりました。 これまでに取得した内容が正しい場合、効率を上げるために何かする必要がありますか?正しくない場合はどうすればよいですか?私は見当もつかない。
注意してくださいドキュメントには次のように記載されています。Hibernateは現在のセッション追跡の3つの方法を提供します。 「スレッド」ベースの方法は、本番環境での使用を目的としたものではありません。これは、このようなプロトタイピングやチュートリアルに役立つだけです。
Hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/myDB</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="show_sql">true</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<!-- <property name="hbm2ddl.auto">update</property>-->
<mapping class="com.myProject.entities.users" />
...
現在の構成とコード
答えに基づいて、 ドキュメントのこの部分 muの現在の構成は次のとおりです。
public class HibernateUtil {
private static SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
Configuration configuration = new Configuration();
return configuration.configure()
.buildSessionFactory(
new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.build());
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
そして、コードは次のようになります
final Session session = HibernateUtil.getSessionFactory().openSession();
try {
final Transaction tx = session.beginTransaction();
try {
...
以前の構成とコード
public class HibernateUtil {
private static ServiceRegistry serviceRegistry;
private static final ThreadLocal<Session> threadLocal = new ThreadLocal();
private static SessionFactory sessionFactory;
private static SessionFactory configureSessionFactory() {
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
} catch (HibernateException e) {
System.out.append("** Exception in SessionFactory **");
e.printStackTrace();
}
return sessionFactory;
}
static {
try {
sessionFactory = configureSessionFactory();
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
private HibernateUtil() {
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getSession() throws HibernateException {
Session session = threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession() : null;
threadLocal.set(session);
}
return session;
}
public static void rebuildSessionFactory() {
try {
sessionFactory = configureSessionFactory();
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
if (session.isOpen()) {
session.close();
}
}
}
}
トランザクションにアクセスしてコマンドを送信するためのコード
final Session session = HibernateUtil.getSession();
try {
final Transaction tx = session.beginTransaction();
try {
//Commands related to query go here
if (!tx.wasCommitted()) {
tx.commit();
}
if (session.isOpen()) {
session.close();
}
return true;
} catch (Exception e) {
tx.rollback();
return false;
}
} finally {
HibernateUtil.closeSession();
}
return false;
Spring 1.0Hibernate統合スタイルを思い出させるTreadUtilクラスを削除します。 Hibernate4への移行を計画している場合。
Hibernate 4 bootstrap メカニズムに依存する必要があるという事実に加えて、コードには次の問題もあります。
セッションファクトリの再構築が同期されていません
synchronized(HibernateUtil.class) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
}
Nullに設定したことがなく、セッションファクトリが静的ブロックに初期化されているため、再構築が必要な理由がわかりません。
HibernateコードをHibernateUtil.openSession()try/finallyブロックで常にラップする必要がある場合は、ビジネスロジックとトランザクションロジックを混在させながら、多くのセッション管理ロジックを複製します。これは、単一責任の原則に違反します。
それでもHibernateUtilを手放したくない場合は、少なくとも JDBCTemplate と同様のメカニズムを使用して、Callableでビジネスコードを提供しながら、テンプレートメソッドでセッション/トランザクション管理を抽象化できます。 、あなたにとっては次のようになります:
interface SessionCallback<T> {T doInSession(Session session);}
class HibernateUtil {
public T execute(SessionCallback<T> action) {
try{
//open session
//open transcation
T result = action.doInSession(sessionFactory.getCurrentSession());
//commit tx
return result;
}
catch(RuntimeException e) {
//rollback tx
throw e;
}
finally {
//close session
}
}
}
HibernateUtil.execute(new SessionCallback<Void>() {
public Void doInSession(Session session) {
session.createQuery(...);
return null;
}
});
final customerID = ...
Customer customer = HibernateUtil.execute(new SessionCallback<Customer>() {
public Customer doInSession(Session session) {
return (Customer) session.get(Customer.class, customerID);
return null;
}
});
コードを見ると、リクエストごとのセッションアクセスイディオムを使用したJDBCリソースローカルトランザクションが必要であることがわかります。つまり、ThreadLocalSessionContextが必要です。
hibernate.current_session_context_class=thread
hibernate.transaction.factory_class=JDBCTransactionFactory
エクストラ
JPAに切り替えて、Hibernateプロパティをpersistence.xmlに移動することも検討してください。
必要なのは、アプリケーション内のSessionFactoryの単一インスタンスへのアクセスだけです。
以下の情報はすべて(利用可能)Hibernate 4.3マニュアルの章 2.2。コンテキストセッション および 13。トランザクションと並行性 からのものです。
「A SessionFactory は作成に費用がかかるスレッドセーフなオブジェクトであり、すべてのアプリケーションスレッドで共有することを目的としています。通常はアプリケーションの起動時に、構成インスタンスから1回作成されます。」
"A セッション は安価でスレッドセーフではないオブジェクトであり、一度使用してから破棄する必要があります:単一のリクエスト、会話、または単一の作業単位。」
「作業単位」がなく、(バンドルされた)クエリと更新の束だけがある場合は、 非管理環境 の最初のイディオムに従ってください(前述の第13章から)。そして、これがパフォーマンスの問題(*)をもたらすことを実証できない限り、それが すべての悪の根 であるため、最適化を試みないでください。
「作業単位」または「要求ごとのセッション」がある場合、質問のHibernateUtil
は、org.hibernate.context.internal.ThreadLocalSessionContext
をCurrentSessionContext
として使用することで置き換えることができます(前述の2.2章を参照)。以前)および 非管理環境 の2番目のイディオムに従います。
JTAを使用する場合は、ThreadLocalSessionContext
をorg.hibernate.context.internal.JTASessionContext
に置き換え、 JTAの使用 で説明されているイディオムに従います。
「作業単位」について説明している章に注意してください。ソフトウェアの優れたアーキテクチャは、「ビジネストランザクション」と「アプリケーショントランザクション」がアプリケーションにとって何を意味するかを十分に理解している必要があります。
(*)パフォーマンスの問題は、構成の問題によって引き起こされる可能性があります。 この質問 関連ドキュメントがあります ここ Hibernateマニュアルにあります。