Sometimes I get a malformed exception in my application. Exceptions come one after another as the following:
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)
It occurs when a select query is executed on database such as the followings:
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=?
or:
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
The first query is a named query for Archive class like this:
@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;
which is called by this method:
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 && 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;
}
The second one is called by this method:
@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;
}
Both methods should set the database that user chooses by setEntityManager(database);
I do not know what causes to occuring this exception! Does anyone know anything about it?
Most likely the issue is with Thread Safety : I got this error when I was trying to access the tables from two separate threads in parallel from the same user session (same browser page had two ajax requests running in parallel).
Got rid of it when I changed the access to serial. Not sure if this is the same issue with you, worth a try.
I have researched a similar problem for a few days. Supra's answer points me to the right direction: thread safety.
The fact is that Session in Hibernate is not thread-safe, and we should not allow 2 threads access the same session. That is one of possible causes of the error "Flush when cascading is dangerous". Two threads access the same session can cause lots of unexpected behavior, because Hibernate isn't designed for that.
Usually I'd use a framework to do this kind of stuff, but if you need to do it your self, you can make a static ThreadLocal variable.
TL;DR: SessionFactory
is thread-safe, Session
is not. Provide one new Session for each thread (either by do it yourself or utilizing a DI framework)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With