2012-05-18 30 views
7

Đôi khi tôi nhận được một ngoại lệ không đúng định dạng trong ứng dụng của tôi. Trường hợp ngoại lệ đến cái khác như sau:HibernateException: Flush trong khi thác là nguy hiểm

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) 

Nó xảy ra khi một truy vấn chọn được thực hiện trên cơ sở dữ liệu như sau:

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=? 

hay:

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 

Truy vấn đầu tiên là truy vấn được đặt tên cho lớp Lưu trữ như sau:

@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; 

được gọi là bằng phương pháp này:

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

thứ hai được gọi là bằng phương pháp này:

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

Cả hai phương pháp này cần thiết lập cơ sở dữ liệu mà người dùng chọn bởi setEntityManager (cơ sở dữ liệu);

Tôi không biết nguyên nhân gì xảy ra ngoại lệ này! Có ai biết gì về nó không?

+0

câu hỏi là gì? "có thể nó xảy ra một lần nữa" -> phụ thuộc vào mã số – Firo

Trả lời

6

Rất có thể sự cố xảy ra với An toàn chủ đề: Tôi gặp lỗi này khi cố truy cập các bảng từ hai luồng riêng biệt song song với cùng một phiên người dùng (cùng một trang trình duyệt có hai yêu cầu ajax đang chạy song song).

Loại bỏ nó khi tôi thay đổi quyền truy cập nối tiếp. Không chắc chắn nếu đây là vấn đề tương tự với bạn, đáng thử.

+0

bạn có thể giải thích về điều này: "thay đổi quyền truy cập vào nối tiếp"? Tôi không biết điều đó có nghĩa là gì. –

+0

Tôi đơn giản có hai yêu cầu song song với tài nguyên từ các cuộc gọi jquery async, sau đó tôi đã đồng bộ hóa. Đây không phải là giải pháp lý tưởng btw, chỉ sử dụng nó để chẩn đoán và thu hẹp vấn đề cụ thể của bạn. – Supra

+0

oh vì vậy đó là cách .. –

3

Tôi đã nghiên cứu một vấn đề tương tự trong vài ngày. Câu trả lời của Supra hướng tôi đi đúng hướng: an toàn chỉ.

Thực tế là Session trong Hibernate không an toàn với chuỗi và chúng tôi không cho phép 2 chủ đề truy cập cùng một phiên. Đó là một trong những nguyên nhân có thể gây ra lỗi "Flush khi cascading là nguy hiểm". Hai luồng truy cập cùng một phiên có thể gây ra nhiều hành vi không mong muốn, vì Hibernate không được thiết kế cho điều đó.

Thông thường tôi muốn sử dụng một khuôn khổ để thực hiện loại công cụ này, nhưng nếu bạn cần tự làm, bạn có thể tạo biến tĩnh ThreadLocal.

TL; DR: SessionFactory là an toàn chỉ, Session thì không. Cung cấp một Phiên mới cho mỗi chủ đề (hoặc tự mình thực hiện hoặc sử dụng khung DI)

+0

Tôi tin rằng nó gần như là kiến ​​thức cơ bản nhất khi bạn sử dụng JDBC/Hibernate/JPA mà Connection/Session/EntityManager được cho là chỉ được sử dụng dưới một luồng.Không thể tưởng tượng có thực sự trường hợp vi phạm này –

+1

Có, trường hợp tồn tại. Đối với tôi đó là bởi vì tôi mess lên quản lý lối sống trong Castle Windsor (tôi chuyển sang C# stack gần đây), kết quả là phiên không phải là một thread như tôi nghĩ. Nhưng tôi có thể nói từ 3 ngày nghiên cứu, đây không phải là trường hợp duy nhất –

+1

Tôi đã nhìn thấy câu hỏi tương tự trong quá khứ nhưng chủ yếu là cho những ứng dụng cấp đồ chơi hoặc tự học. May mắn là tôi đã không gặp phải những trường hợp như vậy trong cuộc sống phát triển của mình cho các ứng dụng thực tế: P Sử dụng đúng các khung công tác thực sự tiết kiệm rất nhiều rắc rối :) –

Các vấn đề liên quan