2017-02-10 5 views
1

Ich benutze Hibernate auf meinem Server, (Tomcat8, Hibernate, Postgresql). Jedes Ende des Tages mein Code ausgeführt wird (unter Verwendung von Quarz) einen Code, der innerhalb der gespeicherten Prozedur aufruft (Hibernate):Hibernate friert bei Transaktion beginnen Funktion

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); 
} 

Die dailyUpdate Funktion in dem obigen Code wird folgendes tun:

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

(Aufruf der gespeicherten Prozedur mit nativen SQL durch den Ruhezustand).

Wenn ich den Server austrage, macht es normalerweise 2 oder 3 Anrufe. Die nächsten Anrufe enden nie. Ich habe das Problem lokal reproduziert, anstatt jeden Tag den Zeitplan zu setzen, um die Aufgabe jede Minute zu starten. Es hat mir gezeigt, wie diese protokolliert:

Daily Update Auftrag abgeschlossen ============== Es dauerte 7338 ms

Daily Update Auftrag abgeschlossen ======= ======= Es dauerte 6473 ms

...

Daily Update Auftrag abgeschlossen ============== Es dauerte 183.381 ms

So nahm die Verzögerung zu und ich entschied mich zu sehen was passiert ist e. In dem obigen Code, wenn es die

em.getTransaction().begin(); 

es nie und den Stack-Trace beendet auszuführen versucht, unten als Bild gezeigt:

Stacktrace of frozen execution

Was ist der Grund, und wie zu lösen das Problem?

EDIT 1: currentEntityManager und closeCurrentEntityManager Codes:

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

Was ist 'HibernateUtil' und wie funktionieren' closeCurrentEntityManager() 'und' currentEntityManager() '? – Andremoniy

+0

@Andremoniy hat die Frage aktualisiert. Bitte schau es dir an. – maximus

+0

Was ist das Feld "entityManager" in dieser Klasse? – Andremoniy

Antwort

1

Ok, perfekt, nach Details über Entsendung was HibernateUtil, wie zu tun closeCurrentEntityManager() und currentEntityManager() Arbeit, und was entityManager fiels innerhalb dieser Klasse ist alles wird klar.

Schauen Sie sich Ihren Code an. Sie schließt zum einen „aktuellen“ EntityManager:

HibernateUtil.closeCurrentEntityManager();

Aber man sollte diese Tatsache berücksichtigen, dass quartz scheduller in verschiedenen Threads ihre Aufgaben beginnt. So

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

kehrt null (wenn es neue Thread).

Nächster Schritt Sie

EntityManager em = HibernateUtil.currentEntityManager(); 

aufrufen, die auch neue EntityManager schaffen, wie es neue Threads:

em = emf.createEntityManager(); 

Jetzt sehen Sie Screenshot: Ihre beginTransaction() Methoden erwartet für neue Verbindung. Was passiert, ist, dass Sie einen neuen "entitymanager" erstellen, der eine neue Verbindung öffnet, aber nicht schließt. Im Grunde genommen haben Sie keine freien Verbindungen in Ihrem Pool.

Versuchen Sie einfach, HibernateUtil.closeCurrentEntityManager(); in final { ... } Block zu verschieben und erneut zu testen.

+0

Oh, ich dachte, ich hätte es getan, aber falsch am Anfang ... Danke! – maximus

Verwandte Themen