2016-11-05 6 views
0

Ich habe eine Hibernate-Klasse, die 3 verschiedene Sitzungen erfordert. Es verwendet derzeit 2 Sitzungen und funktioniert perfekt. Die erste Sitzung wird verwendet, um Daten von einer externen Datenbank zu lesen. Die zweite Sitzung wird verwendet, um Daten in unserer internen Datenbank zu speichern. Ich füge eine dritte Sitzung hinzu, weil wir die Transaktion verfolgen müssen, unabhängig davon, ob die Haupttransaktion erfolgreich ist oder nicht (das XXXXUpdate-Objekt). Mein Problem ist, dass die neue Sitzung auf tx.commit() hängt.Hibernate hängt an tx.commit

private synchronized void executeUpdate(Long manualUpdateTagIndex) throws Exception { 
    LogPersistenceLoggingContext ctx = new LogPersistenceThreadContext().getLogPersistenceLoggingContext(); 

    DateTime minTriggerDate = parseDateTimeIfNotNull(minTriggerTime); 
    DateTime maxTriggerDate = parseDateTimeIfNotNull(maxTriggerTime); 
    Session webdataSession = null; 
    Session XXXXUpdateSession = null; 
    XXXXUpdate update = new XXXXUpdate(); 
    update.setExecutedAt(new DateTime()); 
    update.setStatus(WebdataUpdateStatus.Success); 

    boolean commit = true; 
    int tagCount = 0; 
    List<Period> tagPeriods = new ArrayList<>(); 
    Map<Long, DateTime> tagIndexes = new LinkedHashMap<>(); 

    try { 

     XXXXUpdateSession = accountingService.openUnmanagedSession(); 
     XXXXUpdateSession.getTransaction().begin(); 
     XXXXUpdateSession.save(update); 

     HierarchicalLogContext logCtx = new HierarchicalLogContext(String.valueOf(update.getId())); 
     ctx.pushLoggingContext(logCtx); 

     ctx.log(logger, Level.INFO, new XXXXLogMarker(), "Executing XXXX data transfer", new Object[]{}); 
     if (webdataSessionFactory == null){ 
      throw new Exception("Failed to obtain webdata session factory. See earlier log entries"); 
     } 
     try { 
      webdataSession = webdataSessionFactory.openSession(); 
     } catch (Exception ex) { 
      update.setStatus(WebdataUpdateStatus.ConnectionError); 
      throw new Exception("Failed to obtain webdata connection", ex); 
     } 

     webdataSession.getTransaction().begin(); 

     if (manualUpdateTagIndex == null) { // automatic tags update 

      XXXXUpdate lastUpdate = (XXXXUpdate) HibernateUtil.getCurrentSpringManagedSession() 
        .createCriteria(XXXXUpdate.class) 
        .add(Restrictions.isNotNull("latestTriggerTimestamp")) 
        .add(Restrictions.eq("status", WebdataUpdateStatus.Success)) 
        .add(Restrictions.eq("manualUpdate", false)) 
        .addOrder(Order.desc("latestTriggerTimestamp")) 
        .setMaxResults(1).uniqueResult(); 

      DateTime lastUpdatedDate = Period.defaultEffectiveInstant; 
      if (minTriggerDate != null) { 
       lastUpdatedDate = minTriggerDate; 
      } 

      if (lastUpdate != null && lastUpdate.getLatestTriggerTimestamp() != null) { 
       lastUpdatedDate = lastUpdate.getLatestTriggerTimestamp(); 
       ctx.log(logger, Level.INFO, new XXXXLogMarker(), 
         "Querying for tag event triggers newer than last update timestamp [" + lastUpdate.getLatestTriggerTimestamp() + "]", new Object[]{}); 
      } else { 
       ctx.log(logger, Level.INFO, new XXXXLogMarker(), "Update has never run. Catching up with history", new Object[]{}); 
      } 

      @SuppressWarnings("unchecked") 
      List<XXXXProcessedTagRequest> processedReqs = HibernateUtil.getCurrentSpringManagedSession() 
        .createCriteria(XXXXProcessedTagRequest.class).list(); 

      Query triggerQuery = webdataSession.createQuery(
        "select trigger, " 
          + "trigger.TagIndex," 
          + "req " 
          + "from XXXXTagEventTrigger as trigger " 
          + "join trigger.req as req " 
          + "where trigger.EventType in (:eventTypes) " 
          + "and trigger.timestamp > :lastUpdateMinusDelta " 
          + (maxTriggerDate != null?"and trigger.timestamp < :maxDate ":"") 
          + "and req.CurrentState = :currentState " 
          + "order by trigger.timestamp,trigger.reqIndex"); 

      triggerQuery.setParameterList("eventTypes", new Object[]{5, 9}); 
      triggerQuery.setParameter("lastUpdateMinusDelta", lastUpdatedDate.minusHours(hoursToKeepProcessedReqs)); 
      if (maxTriggerDate != null){ 
       triggerQuery.setParameter("maxDate", maxTriggerDate); 
      } 
      triggerQuery.setParameter("currentState", 2); 

      @SuppressWarnings("unchecked") 
      List<Object[]> allTriggers = triggerQuery.list(); 

      List<Object[]> unprocessedTriggers = removeProcessedTags(new ArrayList<Object[]>(allTriggers),processedReqs,ctx); 

      for (Object[] row : unprocessedTriggers) { 
       XXXXTagEventTrigger trigger = (XXXXTagEventTrigger) row[0]; 

       if (lastUpdatedDate == null || lastUpdatedDate.isBefore(trigger.getTimestamp().getMillis())) { 
        lastUpdatedDate = new DateTime(trigger.getTimestamp()); 
       } 

       tagIndexes.put((Long) row[1], new DateTime(trigger.getTimestamp())); 

       XXXXProcessedTagRequest processedReq = new XXXXProcessedTagRequest(); 
       processedReq.setReqIndex(((XXXXTagReq)row[2]).getReqIndex()); 
       processedReq.setTimestamp(trigger.getTimestamp()); 

       HibernateUtil.getCurrentSpringManagedSession().save(processedReq); 
      } 

      ctx.log(logger, Level.INFO, new XXXXLogMarker(), 
        "Found [" + unprocessedTriggers.size() + "] tag event triggers on [" + tagIndexes.size() + "] tags", new Object[]{}); 

      update.setLatestTriggerTimestamp(lastUpdatedDate); 
     } else { // manual tag update 
      ctx.log(logger, Level.INFO, new XXXXLogMarker(), "Executing manual update for tag index [" + manualUpdateTagIndex + "]", new Object[]{}); 

      DateTime now = new DateTime(); 
      tagIndexes.put(manualUpdateTagIndex, now); 
      update.setLatestTriggerTimestamp(now); 
      update.setManualUpdate(true); 
     } 

     if (tagIndexes.size() > 0) { 

      int totalTagCount = tagIndexes.size(); 

      while (!tagIndexes.isEmpty()) { 
       List<Long> batchIndexes = new ArrayList<>(); 
       Iterator<Map.Entry<Long, DateTime>> indexIt = tagIndexes.entrySet().iterator(); 

       while (indexIt.hasNext() && batchIndexes.size() < tagBatchSize) { 
        batchIndexes.add(indexIt.next().getKey()); 
        indexIt.remove(); 
       } 

       Map<Long, LocalTag> existingTags = new HashMap<>(); 
       @SuppressWarnings("unchecked") 
       List<LocalTag> existingTagIds = HibernateUtil.getCurrentSpringManagedSession() 
         .createCriteria(LocalTag.class) 
         .add(Restrictions.in("tagIndex", batchIndexes)) 
         .add(Restrictions.eq("currentVersion", true)).list(); 

       for (LocalTag lt : existingTagIds) { 
        existingTags.put(lt.getTagIndex(), lt); 
       } 

       ctx.log(logger, Level.INFO, new XXXXLogMarker(), 
         "Processing tag updates [" + tagCount + "-" + (tagCount + batchIndexes.size()) + "] of [" + totalTagCount + "]", new Object[]{}); 

       Criteria tagCriteria = webdataSession.createCriteria(XXXXTag.class); 
       tagCriteria.add(Restrictions.in("TagIndex", batchIndexes)); 
       if (!includeTestTags) { 
        tagCriteria.add(Restrictions.eq("TestTag", "0")); 
       } 
       tagCriteria.setFetchMode("XXXXTagMS", FetchMode.JOIN); 
       tagCriteria.setFetchMode("XXXXTagPS", FetchMode.JOIN); 
       tagCriteria.setFetchMode("XXXXTagCCList", FetchMode.JOIN); 
       tagCriteria.setFetchMode("XXXXTagTA", FetchMode.JOIN); 
       tagCriteria.setFetchMode("XXXXTagCP", FetchMode.JOIN); 
       tagCriteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); 

       @SuppressWarnings("unchecked") 
       List<XXXXTag> tags = tagCriteria.list(); 

       if (manualUpdateTagIndex != null && tags.isEmpty()) { 
        throw new ValidationException("No tag found for manual update tag index [" + manualUpdateTagIndex + "]"); 
       } 

       for (XXXXTag tag : tags) { 
        update.getProcessedTags().add(updateTag(tag, tagIndexes.get(tag.getTagIndex()), existingTags)); 
        tagCount++; 
        if (fireEventLastActions.contains(tag.getLastAction().trim())) { 
         tagPeriods.add(new Period(tag.getStartTime().getMillis(), tag.getStopTime().getMillis())); 
        } 
       } 

       HibernateUtil.getCurrentSpringManagedSession().flush(); 
       HibernateUtil.getCurrentSpringManagedSession().clear(); 

       webdataSession.clear(); 
      } 
     } else { 
      ctx.log(logger, Level.INFO, new XXXXLogMarker(), "No updates found", new Object[]{}); 
     } 

     HibernateUtil.getCurrentSpringManagedSession() 
     .createQuery("delete XXXXUpdate where executedAt < :purgeDate") 
     .setParameter("purgeDate", new DateTime().minusDays(daysToKeepUpdateHistory)) 
     .executeUpdate(); 

     HibernateUtil.getCurrentSpringManagedSession() 
     .createQuery("delete XXXXProcessedTagRequest where timestamp < :purgeDate") 
     .setParameter("purgeDate", new DateTime().minusHours(hoursToKeepProcessedReqs)) 
     .executeUpdate(); 

     update.setStatus(WebdataUpdateStatus.Success); 
     update.setTagCount(update.getProcessedTags().size()); 

     tagPeriods = Period.merge(tagPeriods); 

     for (Period p : tagPeriods) { 
      XXXXUpdatePeriod oup = new XXXXUpdatePeriod(); 
      oup.setXXXXUpdate(update); 
      oup.setStartDate(p.getStart()); 
      oup.setEndDate(p.getEnd()); 
      update.getPeriods().add(oup); 
     } 

     HibernateUtil.getCurrentSpringManagedSession().flush(); 

     ctx.log(logger, Level.INFO, new XXXXLogMarker(), "XXXX data transfer complete. Transferred [" + tagCount + "] tag updates", new Object[]{}); 

     ctx.popLoggingContext(logCtx); 
    } catch (Exception ex) { 
     HibernateUtil.getCurrentSpringManagedSession().clear(); 
     update.getProcessedTags().clear(); 
     update.setTagCount(0); 
     update.setStatus(WebdataUpdateStatus.TransferError); 
     commit = false; 
     ctx.log(logger, Level.ERROR, new XXXXLogMarker(), "XXXX data transfer failed", new Object[]{}, ex); 
     throw new Exception("XXXX data transfer failed", ex); 
    } finally { 
     try { 

      XXXXUpdateSession.saveOrUpdate(update); 
      XXXXUpdateSession.getTransaction().commit(); 

     } catch (Exception ex) { 
      commit = false; 
      ctx.log(logger, Level.ERROR, new XXXXLogMarker(), "Failed to save XXXX transfer update record", new Object[]{}, ex); 
      throw new Exception("Failed to save XXXX transfer update record", ex); 
     } finally { 
      if (!commit) { 
       webdataSession.getTransaction().rollback(); 
      } else { 
       webdataSession.getTransaction().commit(); 
      } 
      ResourceDisposer.dispose(webdataSession); 
     } 

    } 

} 

Die neue Sitzung ist die XXXXUpdateSession. Der einzige neue Code ist der, der sich auf diese Sitzung bezieht. Es ist eine Art von Timing-Problem, weil, wenn ich Hibernate Debug-Protokollierung verwende, der TX ohne Problem festlegt. Es wird auch festgelegt, wenn ich versuche, den Hibernate Commit() zu debuggen. Ich habe nicht viel Erfahrung mit Winterschlaf, also vermisse ich wahrscheinlich etwas Offensichtliches. Jede Hilfe würde sehr geschätzt werden. Vielen Dank.

Antwort

1

Sie haben zwei Transaktionen webdataSession.getTransaction().begin(); geöffnet, die das Problem verursacht (20 & 37 Zeilen im obigen Code).

Sie können die zweite Transaktion nach der ersten Transaktion öffnen.

Es ist auch keine bewährte Methode, lange Methoden zu verwenden, die sehr schwierig sind, die Probleme zu debuggen und der Alptraum für die Wartung/Unterstützung des Projekts zu werden.

+0

Danke, ich stimme zu. Ich habe es nicht geschrieben. Also, auch wenn die zwei Transaktionen mit verschiedenen Sitzungen verknüpft sind, können sie nicht gleichzeitig geöffnet sein? – user3029642

+0

wo hast du XXXXUpdateSession gelöscht? – developer

+0

Ich habe am Ende der Methode im verschachtelten endlich zugesagt. XXXXUpdateSession.saveOrUpdate (Update); XXXXUpdateSession.getTransaction(). Commit(); Ich habe auch versucht, an der gleichen Stelle zu spülen. Gleiches Ergebnis. – user3029642