title: HibernateException: Flush during cascade is dangerous
body: <p>Sometimes I get a malformed exception in my application. Exceptions come one after another as the following:</p>
  
  <pre><code>Caused by: java.lang.reflect.InvocationTargetException
  at sun.reflect.GeneratedMethodAccessor77.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  at java.lang.reflect.Method.invoke(Method.java:592)
  at org.apache.wicket.RequestListenerInterface.invoke(RequestListenerInterface.java:183)
  ... 22 common frames omitted   
  
  Caused by: org.springframework.orm.jpa.JpaSystemException: Error while commiting the transaction; nested exception is javax.persistence.RollbackException: Error while commiting the transaction
  at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:294)
  at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerSynchronization.convertCompletionException(ExtendedEntityManagerCreator.java:483)
  at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerSynchronization.afterCommit(ExtendedEntityManagerCreator.java:464)
  at org.springframework.transaction.support.TransactionSynchronizationUtils.invokeAfterCommit(TransactionSynchronizationUtils.java:90)
  
  Caused by: javax.persistence.RollbackException: Error while commiting the transaction
  at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:71)
  at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerSynchronization.afterCommit(ExtendedEntityManagerCreator.java:461)
  ... 52 common frames omitted
  
  Caused by: org.hibernate.HibernateException: Flush during cascade is dangerous
  at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:996)
  at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
  at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
  at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
  </code></pre>
  
  <p>It occurs when a select query is executed on database such as the followings:</p>
  
  <pre><code>select archive0_.ARCHIVE_KEY as ARCHIVE1_16_, 
     archive0_.ARCHIVE_DATE as ARCHIVE2_16_, 
     archive0_.ARCHIVE_TYPE as ARCHIVE3_16_, 
     archive0_.DELETION_DATE as DELETION4_16_, 
     archive0_.ENCODING as ENCODING16_, 
     archive0_.FILENAME as FILENAME16_, 
     archive0_.JMSPROPERTIES as JMSPROPE7_16_, 
     archive0_.MESSAGE_ID as MESSAGE8_16_, 
     archive0_.MESSAGE_TYPE as MESSAGE9_16_, 
     archive0_.MESSAGE_VERSION as MESSAGE10_16_, 
     archive0_.PAYLOAD as PAYLOAD16_, 
     archive0_.SERVICE_NAME as SERVICE12_16_, 
     archive0_.TYPE_OF_SERVICE as TYPE13_16_, 
     archive0_.TIME_TO_LIVE as TIME14_16_, 
     archive0_.TRANSACTION_ID as TRANSAC15_16_ 
  from   LOGGING.ARCHIVED_MESSAGES archive0_ 
  where  archive0_.MESSAGE_ID=? and archive0_.SERVICE_NAME=?
  </code></pre>
  
  <p>or:</p>
  
  <pre><code>select audit0_.AUDIT_ID as AUDIT1_17_, 
     audit0_.CODE as CODE17_, 
     audit0_.FLOW_NAME as FLOW3_17_, 
     audit0_.KEY_FIELD_NAME as KEY4_17_, 
     audit0_.KEY_FIELD_VALUE as KEY5_17_, 
     audit0_.LOG_TIME as LOG6_17_, 
     audit0_.MESSAGE_ID as MESSAGE7_17_, 
     audit0_.MESSAGE_SIZE as MESSAGE8_17_, 
     audit0_.MESSAGE_TYPE as MESSAGE9_17_, 
     audit0_.MESSAGE_TYPE_VERSION as MESSAGE10_17_, 
     audit0_.PRIORITY as PRIORITY17_, 
     audit0_.RECEIVER as RECEIVER17_, 
     audit0_.SENDER as SENDER17_, 
     audit0_.SERVICE_NAME as SERVICE14_17_, 
     audit0_.TRANSACTION_ID as TRANSAC15_17_, 
     audit0_.TRANSPORT_ID as TRANSPORT16_17_ 
  from   LOGGING.AUDIT audit0_ 
  where  audit0_.TRANSACTION_ID=? 
  and    (audit0_.LOG_TIME between ? and ?) 
  order by audit0_.LOG_TIME
  </code></pre>
  
  <p>The first query is a named query for Archive class like this:</p>
  
  <pre><code>@Entity
  @Table(schema = "LOGGING", name = "ARCHIVED_MESSAGES")
  @NamedQuery(name = "findArchiveByMessageIdAndServiceName", query = "SELECT ar FROM        Archive ar WHERE ar.messageId = :messageId and ar.serviceName = :serviceName")
  public class Archive implements Serializable {
  private static final long serialVersionUID = 1L;
  </code></pre>
  
  <p>which is called by this method:</p>
  
  <pre><code>public Archive findArchive(String database, Audit audit) {
      LOGGER.debug("findArchive {}", audit);
      setEntityManager(database);
      javax.persistence.Query query;
      Archive archive = null;
  
      // Get the query
      query = em.createNamedQuery("findArchiveByMessageIdAndServiceName");
  
      // Set the parameters
      query.setParameter("messageId", audit.getMessageId());
      query.setParameter("serviceName", audit.getServiceName());
  
      try {
          List archives = query.getResultList();
          if(archives != null &amp;&amp; archives.size() != 0)
              archive = (Archive) archives.get(0);
      } catch (NoResultException e) {
          // Ok so not all audit records have a matching archive but...
      } catch (Exception e) {
          // Any other error is a problem
          LOGGER.error("Failed to find archive", e);
      }
  
      return archive;
  }
  </code></pre>
  
  <p>The second one is called by this method:</p>
  
  <pre><code>@SuppressWarnings("unchecked")
  public Iterator findByCriteria(Criteria criteria, int first, int count) {
      LOGGER.debug("findByCriteria {}", criteria);
      setEntityManager(criteria.getDatabase());
      StringBuffer queryString = new StringBuffer();
      Query query;
  
      queryString.append("SELECT MAX(a.code), MIN(a.logTime), MAX(a.logTime), "
              + "a.transactionId as transactionId, a.sender as sender, a.receiver as receiver ");
  
      //Add the common where clause
      queryString.append(" FROM Audit a where a.logTime BETWEEN :from AND :to");
      // Append the appropriate addition where clauses depending on what
      // values are set 
      if (criteria.getSender() != null
              || criteria.getFilter().getSender() != null) {
          queryString.append(" AND a.sender = :sender");
      }
  
      if (criteria.getReceiver() != null
              || criteria.getFilter().getReceiver() != null) {
          queryString.append(" AND a.receiver = :receiver");
      }
  
      if (criteria.getMessageType() != null
              || criteria.getFilter().getMessageType() != null) {
          queryString.append(" AND a.messageType = :messageType");
      }
      if (criteria.getTransactionId() != null
              || criteria.getFilter().getTransactionId() != null) {
          queryString
                  .append(" AND a.transactionId = :transactionId");
      }
      if (criteria.getKeyFieldValue() != null
              || criteria.getFilter().getKeyFieldValue() != null) {
          queryString
                  .append(" AND UPPER(a.keyFieldValue) LIKE :keyFieldValue");
      }
  
  
      // We want a summary so lets group by the common ids
      queryString.append(" GROUP BY a.transactionId, a.sender, a.receiver ");
  
      // Add order by clause
      if (criteria.getOrderBy() != null) {
          queryString.append(" ORDER BY ");           
          queryString.append(criteria.getOrderBy());          
          queryString.append(criteria.isAscending() ? " ASC" : " DESC");
      }
  
      Session session = ((Session) em.getDelegate()).getSessionFactory().openSession();
      query = session.createQuery(queryString.toString());
      query.setReadOnly(true);
      query.setFetchSize(Integer.valueOf(1000));
      query.setCacheable(true);
      query.setCacheMode(CacheMode.NORMAL);
  
      // Will always have from and to dates
      query.setParameter("from", criteria.getFromDate());
      query.setParameter("to", criteria.getToDate());
  
      // Set remaining parameters depending on what is set
      if (criteria.getSender() != null) {
          query.setParameter("sender", criteria.getSenderValue());
      }
  
      // Override the search criteria with the filter if set
      if (criteria.getFilter().getSender() != null) {
          query.setParameter("sender", criteria.getFilter().getSender());
      }
  
      if (criteria.getReceiver() != null) {
          query.setParameter("receiver", criteria.getReceiverValue());
      }
  
      if (criteria.getFilter().getReceiver() != null) {
          query.setParameter("receiver", criteria.getFilter().getReceiver());
      }
  
      if (criteria.getMessageType() != null) {
          query.setParameter("messageType", criteria.getMessageTypeValue());
      }
  
      if (criteria.getFilter().getMessageType() != null) {
          query.setParameter("messageType", criteria.getFilter()
                  .getMessageType());
      }
      if (criteria.getTransactionId() != null) {
          query.setParameter("transactionId", criteria.getTransactionId());
      }
  
      if (criteria.getFilter().getTransactionId() != null) {
          query.setParameter("transactionId", criteria.getFilter()
                  .getTransactionId());
      }
      if (criteria.getKeyFieldValue() != null) {
          query.setParameter("keyFieldValue", "%"
                  + criteria.getKeyFieldValue().toUpperCase() + "%");
      }
  
      if (criteria.getFilter().getKeyFieldValue() != null) {
          query.setParameter("keyFieldValue", "%"
                  + criteria.getFilter().getKeyFieldValue().toUpperCase()
                  + "%");
      }
      // Set the limits       
      query.setFirstResult(first);
      query.setMaxResults(PAGE_SIZE);
  
      Iterator iterator = query.list().iterator();
      session.close();
      return iterator;
  }
  </code></pre>
  
  <p>Both methods should set the database that user chooses by setEntityManager(database);</p>
  
  <p>I do not know what causes to occuring this exception! Does anyone know anything about it?</p>