有时我的应用程序出现格式错误的异常。例外如下:
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)
在数据库上执行select查询时会发生这种情况,如下所示:
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=?
或:
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
第一个查询是Archive类的命名查询,如下所示:
@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;
由此方法调用:
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;
}
第二个是通过这种方法调用的:
@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;
}
两种方法都应该设置用户通过setEntityManager(数据库)选择的数据库;
我不知道是什么原因导致发生此异常!有人知道吗?
答案 0 :(得分:7)
最有可能的问题是线程安全: 当我尝试从同一个用户会话并行访问两个独立线程中的表时,我遇到了这个错误(同一个浏览器页面有两个并行运行的ajax请求)。
当我改变对串行的访问权限时,摆脱它。不确定这是否与您的问题相同,值得一试。
答案 1 :(得分:3)
我已经研究了几天类似的问题了。 Supra的回答指出了正确的方向:线程安全。
事实是Hibernate中的Session不是线程安全的,我们不应该让2个线程访问同一个会话。这是错误的可能原因之一“当级联危险时冲洗”。两个线程访问同一会话可能会导致许多意外行为,因为Hibernate不是为此设计的。
通常我会使用框架来做这种事情,但如果你需要自己动手,你可以制作一个静态ThreadLocal变量。
TL; DR :SessionFactory
是线程安全的,Session
不是。为每个线程提供一个新的会话(通过自己动手或使用DI框架)