2017-02-10 83 views
1

我用我的服務器上的Hibernate,(tomcat8,休眠和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(); 

它永遠不會完成和堆棧跟蹤如下所示的圖像:

Stacktrace of frozen execution

的原因是什麼,以及如何解決問題?

編輯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(); 
    } 
} 
+0

什麼是'HibernateUtil',以及closeCurrentEntityManager()和currentEntityManager()如何工作? – Andremoniy

+0

@Andremoniy更新了問題。請看一下。 – maximus

+0

這個類裏面的'entityManager'字段是什麼? – Andremoniy

回答

1

好,完善,發佈關於什麼是HibernateUtil,細節後怎麼辦closeCurrentEntityManager()currentEntityManager()工作,這是什麼類,裏面的一切entityManager fiels變得清晰。

看看你的代碼。你首先關閉「當前」的實體管理器:

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 { ... }塊並再次測試。

+0

噢,我以爲我做到了,但錯誤地將它放在開頭......謝謝! – maximus