簡體   English   中英

Hibernate 在事務開始函數時凍結

[英]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();
    }
}

好的,完美,在發布了有關什么是HibernateUtilcloseCurrentEntityManager()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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM