2017-02-10 3 views
1

내 서버 (tomcat8, hibernate, postgresql)에서 최대 절전 모드를 사용하고 있습니다. 내 코드가 실행되는 일의 모든 끝 저장 프로 시저 내에서 호출하는 코드 (석영을 사용) (최대 절전 모드) :트랜잭션 시작 함수에서 최대 절전 모드로 전환

public void dailyUpdate() { 
    String sql = "select count(*) FROM daily_update()"; 
    EntityManager em = HibernateUtil.currentEntityManager(); 
    em.createNativeQuery(sql).getSingleResult(); 
} 
:

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 기능은 다음을 수행한다

(최대 절전 모드에서 원시 SQL을 사용하는 저장 프로 시저 호출).

서버를 실행할 때 처음 2 ~ 3 번은 정상적으로 호출됩니다. 다음 호출은 끝나지 않습니다. 저는 로컬로이 문제를 재현했습니다. 매일 1 분마다 작업을 시작하는 일정을 정했습니다. 그것은 나에게 다음과 같이 기록 하였다 :

매일 업데이트 작업 ============== 완료 그것은 7338했다

는 매일 업데이트 작업 완료 MS ======= =======은 6473 MS

...

매일 업데이트 작업 ============== 완료 그것은했다 183381 MS

했다 그래서 지연이 증가했고 내부적으로 진행되는 것을보기로 마음 먹었다. 이자형. 이유는 무엇

Stacktrace of frozen execution

어떻게 해결하는 방법 : 그것이 완료 결코

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

'HibernateUtil'이란 무엇이며'closeCurrentEntityManager()'와'currentEntityManager()'는 어떻게 작동합니까? – Andremoniy

+0

@Andremoniy이 질문을 업데이트했습니다. 이것을 봐주세요. – maximus

+0

이 클래스 안에 'entityManager' 필드 란 무엇입니까? – Andremoniy

답변

1

좋아, 완벽한, HibernateUtil 무엇인지에 대한 세부 정보를 게시 한 후 수행하는 방법이 클래스, 모든 내부 entityManager fiels, 그리고 무엇 closeCurrentEntityManager()currentEntityManager() 일 분명해진다.

코드를 확인하십시오. 당신은 먼저 "현재"엔티티 관리자 종료 :

HibernateUtil.closeCurrentEntityManager();

하지만 당신은 고려 quartz scheduller 다른 스레드의 작업을 시작한다는 그 사실을 고려해야한다. 따라서

public static void closeCurrentEntityManager() { 
    EntityManager s = (EntityManager) entityManager.get(); 

은 새로운 스레드 인 경우 null을 반환합니다.

다음 단계는 호출이 새 스레드이기 때문에 새로운 EntityManager을 만듭니다

EntityManager em = HibernateUtil.currentEntityManager(); 

:

em = emf.createEntityManager(); 

이제 스크린 샷을보고 : 당신의 beginTransaction() 방법은 새로운 연결을 기다리고 있습니다. 여기서 일어나는 일은 새로운 연결을 열지 만 그것을 닫지 않는 새로운 entitmanager를 만드는 것입니다. 그래서 기본적으로 수영장에서 무료로 연결됩니다.

HibernateUtil.closeCurrentEntityManager();final { ... } 블록으로 이동시키고 다시 테스트 해보십시오.

+0

오, 내가 해냈다 고 생각했지만, 처음에 틀리게 넣었습니다 ... 고마워요! – maximus