2017-02-10 24 views
1

Я использую Hibernate на своем сервере, (tomcat8, hibernate, postgresql). Каждый конец дня мой код работает (с использованием Quartz) код, который вызывает внутри хранимой процедуры (спящий режим):Hibernate зависает при запуске транзакции

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

В чем причина и как решить проблема?

EDIT 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

 Смежные вопросы

  • Нет связанных вопросов^_^