[英]Hibernate freezes at transaction begin function
我在我的服務器上使用 Hibernate(tomcat8、hibernate、postgresql)。 每天結束時,我的代碼都會運行(使用 Quartz)一些代碼,這些代碼在存儲過程(休眠)中調用:
public void execute(JobExecutionContext context)
throws JobExecutionException {
log.info("=========Start daily update==========");
long startTime = System.currentTimeMillis();
boolean transactionCompleted = false;
int retryCount = HibernateUtil.RETRY_COUNT;
HibernateUtil.closeCurrentEntityManager();
EntityManager em = HibernateUtil.currentEntityManager();
while (!transactionCompleted)
{
try {
em.getTransaction().begin();
dailyUpdateDao.dailyUpdate();
em.getTransaction().commit();
transactionCompleted = true;
} catch (PersistenceException ex) {
if (!HibernateUtil.isDeadlockException(ex) || retryCount == 0) {
log.error("non deadlock error", ex);
throw ex;
}
log.error("deadlock detected. Retrying {}", HibernateUtil.RETRY_COUNT - retryCount);
retryCount--;
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
try {
Thread.sleep(HibernateUtil.sleepIntervalWhenDeadlockDetected(retryCount));
} catch(Exception sleepex) {
log.error("non deadlock sleep ex", ex);
throw ex;
}
}
}
log.info("===========Daily Update Job Completed ============== It took {} ms", System.currentTimeMillis() - startTime);
}
上面代碼中的 dailyUpdate 函數執行以下操作:
public void dailyUpdate() {
String sql = "select count(*) FROM daily_update()";
EntityManager em = HibernateUtil.currentEntityManager();
em.createNativeQuery(sql).getSingleResult();
}
(通過休眠使用本機 sql 調用存儲過程)。
當我運行服務器時,它通常會先進行 2 或 3 次調用。 下一次調用永遠不會結束。 我在本地重現了這個問題,而不是每天我把計划安排為每 1 分鍾開始一次任務。 它向我展示了這樣的日志:
每日更新作業已完成 ============== 耗時 7338 毫秒
每日更新作業已完成 ============== 耗時 6473 毫秒
...
每日更新作業已完成 ============== 耗時 183381 毫秒
所以延遲增加了,我決定看看里面發生了什么。 在上面的代碼中,當它嘗試執行
em.getTransaction().begin();
它永遠不會完成,堆棧跟蹤如下圖所示:
是什么原因以及如何解決問題?
編輯 1: currentEntityManager 和 closeCurrentEntityManager 代碼:
public class HibernateUtil {
...
private static EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(PERSISTENT_UNIT);
public static EntityManager currentEntityManager(EntityManagerFactory emf)
throws HibernateException {
EntityManager em = (EntityManager) entityManager.get();
if (em == null||!em.isOpen()) {
em = emf.createEntityManager();
entityManager.set(em);
}
return em;
}
public static void closeCurrentEntityManager() {
EntityManager s = (EntityManager) entityManager.get();
try {
if (s != null) {
if (s.getTransaction().isActive()) {
if (s.getTransaction().getRollbackOnly()) {
s.getTransaction().rollback();
} else {
s.getTransaction().commit();
}
}
s.close();
}
} finally {
entityManager.remove();
}
}
好的,完美,在發布了有關什么是HibernateUtil
、 closeCurrentEntityManager()
和currentEntityManager()
工作原理以及該類中的entityManager
字段的詳細信息之后,一切都變得清晰了。
看看你的代碼。 您首先關閉“當前”實體管理器:
HibernateUtil.closeCurrentEntityManager();
但是您應該考慮到quartz scheduller
程序在不同線程中啟動其任務的事實。 所以
public static void closeCurrentEntityManager() {
EntityManager s = (EntityManager) entityManager.get();
將返回null
(如果它是新線程)。
您調用的下一步
EntityManager em = HibernateUtil.currentEntityManager();
這也將創建新的EntityManager
因為它是新線程:
em = emf.createEntityManager();
現在看看你的截圖:你的beginTransaction()
方法等待新的連接。 這里發生的事情是您創建了新的 entitmanager,它會打開新連接,但不要關閉它。 所以基本上你的池中沒有免費連接。
只需嘗試移動HibernateUtil.closeCurrentEntityManager();
進入final { ... }
塊並再次測試。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.