Hibernate を使用して postgre データベースに接続するアプリケーションがあります。C3P0 を接続プールとして使用します。
persistence.xml:
<persistence-unit name="tv-europe-core" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider>
- -クラス - -
<プロパティ> <プロパティ名="hibernate.dialect" 値="org.hibernate.dialect.PostgreSQLDialect" />
<プロパティ名="hibernate.connection.password" 値="---パスワード---" />
< property name="hibernate.connection.url" value="---database---" />
<property name="hibernate.connection.username" value="---username---" /><property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
<property name="hibernate.connection.release_mode" value="after_statement" />
<property name="hibernate.connection.autocommit " 値="false" /><property name="hibernate.c3p0.minPoolSize" value="5"/>
<property name="hibernate.c3p0.maxPoolSize" value="60"/>
<property name="hibernate.c3p0.maxIdleTime" value=" 10"/>
<property name="hibernate.c3p0.idleConnectionTestPeriod" value="5"/>
<property name="hibernate.c3p0.testConnectionOnCheckin" value="true"/>
</properties>
</persistence-unit>
オブジェクトの保存:
public Entity saveOrUpdate(Entity entity, User u) { EntityTransaction tx = EntityManagerHelper.getEntityManager().getTransaction(); try { if(!tx.isActive()) tx.begin(); Entity result = null; if (getID(entity) == null) { EntityManagerHelper.getEntityManager().persist(entity); } else { result = EntityManagerHelper.getEntityManager().merge(entity); } tx.commit(); return result; } catch (RuntimeException re) { re.printStackTrace(); tx.rollback(); throw re; } }
オブジェクトを読み込んでいます:
@SuppressWarnings("unchecked")
public List<Entity> findByProperty(String propertyName, final Object value,
final int... rowStartIdxAndCount) {
try {
final String queryString = "select model from " + clazz.getName()
+ " model where model." + propertyName + "= :propertyValue";
Query query = EntityManagerHelper.getEntityManager().createQuery(
queryString);
query.setParameter("propertyValue", value);
if (rowStartIdxAndCount != null && rowStartIdxAndCount.length > 0) {
int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);
if (rowStartIdx > 0) {
query.setFirstResult(rowStartIdx);
}
if (rowStartIdxAndCount.length > 1) {
int rowCount = Math.max(0, rowStartIdxAndCount[1]);
if (rowCount > 0) {
query.setMaxResults(rowCount);
}
}
}
final List<Entity> result = query.getResultList();
return result;
} catch (RuntimeException re) {
re.printStackTrace();
throw re;
}
}
EntityManagerFactory の作成と EntityManager の取得:
private static EntityManagerFactory emf;
private static final ThreadLocal<EntityManager> threadLocal = new ThreadLocal<EntityManager>();
public static EntityManager getEntityManager() throws HibernateException {
EntityManager session = (EntityManager) threadLocal.get();
if (session == null || !session.isOpen()) {
session = (emf != null) ? emf.createEntityManager()
: null;
threadLocal.set(session);
}
return session;
}
問題は、データベース接続が何度も「トランザクションでアイドル」状態のままになり、その後、この接続が返されないことです。数日後、接続数がプールの最大サイズを超えたため、アプリケーションが応答を停止します。
hibernate hibernate.connection.autocommit が有効になっている場合、これらの接続は「トランザクションでアイドル状態」にはなりませんが、それでも何らかの理由でブロックされ、結果として生じる問題は同じです。
何か間違ったことをしていませんか (構成が不足しているなど)?
熱心な読み込みのみを使用する場合、問題がないことに気付きました。しかし、パフォーマンスのために遅延読み込みを使用する必要があります。EntityManagerFactory を明示的に閉じる必要がありますか? アプリが非常に長い間機能する必要があり、誰かが永続オブジェクトを操作しているときにアプリをリセットすることはできないと思うので、そうでないことを願っています.
ログには次のように表示されますが、それが何らかの形で問題に関連しているかどうかはわかりません。
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:491)
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:191)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.dest royResource(C3P0PooledConnectionPool.java:470)
at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.ja va:964)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunn er.java:547)
助けてくれてありがとう!:)