2013-03-11 109 views
3

我使用Hibernate 4.0 Final和ojdbc6來開發我的Web應用程序。除非我嘗試插入新的父/子關係,否則一切都可以。首先,這些都是實體:當我提交事務時違反了完整性約束

@Entity 
@Table(name = "EMPLOYEE") 
public class Employee implements Serializable, Cloneable { 
    @Id 
    @SequenceGenerator(name = "seq", sequenceName = "P_SEQ") 
    @GeneratedValue(generator = "seq") 
    @Column(name = "ID_EMPLOYEE") 
    private long idEmployee; 
    ...... 
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "employee", orphanRemoval = true) 
    @Fetch(FetchMode.SELECT) 
    @BatchSize(size = 10) 
    private Set<Address> addresses; 
    ...... 
} 

@Entity 
@Table(name = "ADDRESS") 
public class Address implements Serializable, Cloneable, Comparable {  
    @Id 
    @SequenceGenerator(name = "seq", sequenceName = "P_SEQ") 
    @GeneratedValue(generator = "seq") 
    @Column(name = "ID_ADDRESS") 
    private long idAddress; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "ID_EMPLOYEE") 
    private Employee employee; 
    ....... 
} 

讓我們來看看這兩個場景:

  1. 僱員已經存在,我嘗試將新地址添加到它 - > 它可以正常工作。
  2. 員工還不存在,我嘗試創建一個新員工。兩種不同的情況:
    • a)我只插入一名員工(沒有地址) - >它正常工作。
    • b)我插入和員工及其地址 - >它失敗。我不得不說這必須是一個原子事務。我的意思是,我需要立即創建(保存)一個員工和一個地址。

這是事務處理程序:

public static void save(Employee employee) throws HibernateException, Exception { 
    Session session = HibernateUtil.getCurrentSession(); 
    session.beginTransaction(); 
    try { 
     session.saveOrUpdate(employee); 
    } catch (Exception ex) { 
     session.refresh(employee); 
     HibernateUtil.closeSession(); 
     throw ex; 
    } 
    HibernateUtil.commitTransaction(); 
} 
public static void commitTransaction() throws Exception { 
    Transaction tx = getSessionFactory().getCurrentSession().getTransaction(); 
    try { 
     if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) { 
      tx.commit(); 
     } 
    } catch (Exception ex) { 
     tx.rollback(); 
     throw ex; 
    } finally { 
     closeSession(); 
    } 
} 

正如你可以想像,在2.B情況下是一個我很擔心。我調試的交易,這是我所得到的,當我調用save()方法(這是一個DAO類):

  1. session.saveOrUpdate(員工)方法成功執行(我可以檢查保存的員工是否有地址)。此外,它的idEmployee已正確設置(取自序列),並且地址綁定到該員工,並具有有效的idAddress(也取自該序列)。
  2. 在執行commitTransaction()方法的過程中,我得到org.hibernate.exception.ConstraintViolationException,雖然idEmployeeidAddress先前都已正確設置。

簡而言之,異常在提交過程中出現。這就像是這樣開始提交孩子(地址)而不是父母(員工)。

我在做什麼錯?有誰能夠幫助我?提前致謝。

已更新。以上,你可以看到問題中涉及的兩個類的主要部分。現在,在這裏,除了追蹤異常外,您還可以調用它們。他們按照他們所稱的順序。

屬於該DataBacking類:

public void save(ActionEvent event) { 
    try { 
     EmployeeDAO.save(selectedEmployee); 
     newEmployee(); //reset the employee and its collections 
    } catch (ConstraintViolationException ex) { 
     Utilities.addFacesMessage(FacesMessage.SEVERITY_WARN, ex.getMessage(), ""); 
    } catch (Exception ex) { 
     Utilities.log("error", ex.getCause().toString()); 
     Utilities.addFacesMessage(FacesMessage.SEVERITY_WARN, ex.getMessage(), ""); 
    } 
} 

屬於該EmployeeDAO類:

public static void save(Employee employee) throws HibernateException, Exception { 
    Session session = HibernateUtil.getCurrentSession(); 
    session.beginTransaction(); 
    try { 
     session.saveOrUpdate(employee); 
    } catch (Exception ex) { 
     session.refresh(employee); 
     HibernateUtil.closeSession(); 
     throw ex; 
    } 
    HibernateUtil.commitTransaction(); 
} 

屬於HibernateUtil類:

public static void commitTransaction() throws Exception { 
    Transaction tx = getSessionFactory().getCurrentSession().getTransaction(); 
    try { 
     if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) { 
      tx.commit(); 
     } 
    } catch (Exception ex) { 
     tx.rollback(); 
     throw ex; 
    } finally { 
     closeSession(); 
    } 
} 

權後,該EmployeeDAO.save ()方法調用session.SaveOrUpdate(employee),我得到以下跟蹤:

2013-03-12 07:22:55,958 [DEBUG, org.hibernate.internal.SessionImpl] Opened session at timestamp: 13630693759 
2013-03-12 07:22:57,584 [DEBUG, org.hibernate.engine.transaction.spi.AbstractTransactionImpl] begin 
2013-03-12 07:22:57,585 [DEBUG, org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] Obtaining JDBC connection 
2013-03-12 07:22:57,586 [DEBUG, org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] Obtained JDBC connection 
2013-03-12 07:22:57,587 [DEBUG, org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction] initial autocommit status: true 
2013-03-12 07:22:57,587 [DEBUG, org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction] disabling autocommit 
2013-03-12 07:23:00,285 [DEBUG, org.hibernate.SQL] 
    select 
     P_SEQ.nextval 
    from 
     dual 
2013-03-12 07:23:00,361 [DEBUG, org.hibernate.id.SequenceGenerator] Sequence identifier generated: BasicHolder[java.lang.Long[5665]] 
2013-03-12 07:23:00,365 [DEBUG, org.hibernate.event.internal.AbstractSaveEventListener] Generated identifier: 5665, using strategy: org.hibernate.id.SequenceGenerator 
2013-03-12 07:23:00,411 [DEBUG, org.hibernate.SQL] 
    select 
     P_SEQ.nextval 
    from 
     dual 
2013-03-12 07:23:00,417 [DEBUG, org.hibernate.id.SequenceGenerator] Sequence identifier generated: BasicHolder[java.lang.Long[5666]] 
2013-03-12 07:23:00,421 [DEBUG, org.hibernate.event.internal.AbstractSaveEventListener] Generated identifier: 5666, using strategy: org.hibernate.id.SequenceGenerator 

而且在提交之後已被調用:

2013-03-12 07:24:53,288 [DEBUG, org.hibernate.engine.transaction.spi.AbstractTransactionImpl] committing 
2013-03-12 07:24:53,336 [DEBUG, org.hibernate.event.internal.AbstractFlushingEventListener] Processing flush-time cascades 
2013-03-12 07:24:53,343 [DEBUG, org.hibernate.event.internal.AbstractFlushingEventListener] Dirty checking collections 
2013-03-12 07:24:53,403 [DEBUG, org.hibernate.engine.internal.Collections] Collection found: [org.svq.pol.gesper.bean.Employee.addresses#5665], was: [<unreferenced>] (initialized) 
2013-03-12 07:24:53,439 [DEBUG, org.hibernate.event.internal.AbstractFlushingEventListener] Flushed: 2 insertions, 0 updates, 0 deletions to 2 objects 
2013-03-12 07:24:53,440 [DEBUG, org.hibernate.event.internal.AbstractFlushingEventListener] Flushed: 1 (re)creations, 0 updates, 0 removals to 1 collections 
2013-03-12 07:24:53,453 [DEBUG, org.hibernate.internal.util.EntityPrinter] Listing entities: 
2013-03-12 07:24:53,454 [DEBUG, org.hibernate.internal.util.EntityPrinter] org.svq.pol.gesper.bean.Address{address=fasdf, pc=, city=fadsf, idAddress=5666, operator=xxxxx, province=, telef2=, movDate=Tue Mar 12 07:21:15 CET 2013, telef1=, employee=org.svq.pol.gesper.bean.Employee#5665, version=0} 
2013-03-12 07:24:53,456 [DEBUG, org.hibernate.internal.util.EntityPrinter] org.svq.pol.gesper.bean.Employee{surname=fadsf, user=null, dob=Tue Jan 01 00:00:00 CET 1980, address=[org.svq.pol.gesper.bean.Address#5666], pob=fadsf, operator=xxxxx, movDate=Tue Mar 12 07:21:15 CET 2013, version=0, name=fasdf, gender=H, idEmployee=5665, id=12345678} 
2013-03-12 07:24:53,572 [DEBUG, org.hibernate.SQL] 
    insert 
    into 
     EMPLOYEE  
    (SURNAME, ID, MOV_DATE, DOB, GENDER, POB, OPERATOR, USER, VERSION, ID_EMPLOYEE) 
    values 
     (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
2013-03-12 07:24:53,793 [DEBUG, org.hibernate.SQL] 
    insert 
    into 
     ADDRESS 
    (pc, address, MOV_DATE, OPERATOR, ID_EMPLOYEE, city, province, telef_1, telef_2, version, ID_ADDRESS)   
    values 
     (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
2013-03-12 07:24:53,943 [DEBUG, org.hibernate.engine.jdbc.spi.SqlExceptionHelper] ORA-02291: integrity constraint (PERPLADM.ADDRESS_EMPLOYEE_FK) violated - parent key not found 
[n/a] 
java.sql.SQLIntegrityConstraintViolationException: ORA-02291: integrity constraint (PERPLADM.ADDRESS_EMPLOYEE_FK) violated - parent key not found 

    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445) 
    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396) 
    at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:879) 
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450) 
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192) 
    at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531) 
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207) 
    at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1044) 
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1329) 
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3584) 
    at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3665) 
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1352) 
    at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 
    at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:122) 
    at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81) 
    at $Proxy46.executeUpdate(Unknown Source) 
    at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:56) 
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2849) 
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3290) 
    at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:80) 
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:273) 
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:265) 
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:186) 
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:323) 
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52) 
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1081) 
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:315) 
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101) 
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175) 
    at org.svq.pol.gesper.utility.HibernateUtil.commitTransaction(HibernateUtil.java:57) 
    at org.svq.pol.gesper.dao.EmployeeDAO.save(EmployeeDAO.java:110) 
    at org.svq.pol.gesper.backing.DataBacking.save(DataBacking.java:498) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at org.apache.el.parser.AstValue.invoke(AstValue.java:262) 
    at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278) 
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) 
    at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:148) 
    at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88) 
    at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:769) 
    at javax.faces.component.UICommand.broadcast(UICommand.java:300) 
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794) 
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259) 
    at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) 
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) 
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) 
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:409) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169) 
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168) 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) 
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929) 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405) 
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:964) 
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515) 
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) 
    at java.lang.Thread.run(Thread.java:722) 
2013-03-12 07:24:54,027 [WARN, org.hibernate.engine.jdbc.spi.SqlExceptionHelper] SQL Error: 2291, SQLState: 23000 
2013-03-12 07:24:54,027 [ERROR, org.hibernate.engine.jdbc.spi.SqlExceptionHelper] ORA-02291: integrity constraint (PERPLADM.ADDRESS_EMPLOYEE_FK) violated - parent key not found 
+0

向我們展示代碼,並粘貼異常的完整堆棧跟蹤。 – 2013-03-11 08:36:50

+0

我已經用涉及的代碼和異常的堆棧跟蹤更新了我的問題。對不起,延誤了。 – Julio 2013-03-12 07:21:13

+0

我終於找到了我自己的問題的一個部分答案,我在最後添加了。 – Julio 2013-03-16 12:37:21

回答

9

後幾天爲此而努力,我終於發現了什麼問題是,很明顯,該解決方案。據我所知,上面顯示的映射是正確的(至少,應用程序正常工作)。唯一的問題是數據庫中有插入序列的觸發器。這樣,每次我嘗試插入一個僱員(和它的地址)時,Hibernate給了我兩個序列號(一個用於父項,另一個用於子項),正確設置了這兩個序號。然而,在提交的確切時刻,Oracle給了我兩個序列號,這次我錯誤地設置了,我的意思是,外鍵與父主鍵不匹配。

但是,因爲我需要觸發器,我必須再做一步:我必須修改這些,以便檢查:new.ID的值是否爲NULL。如果是這樣,這意味着觸發器已經從外部Hibernate(即另一個應用程序)觸發,因此我從序列中取出nextval,否則我會保留來自Hibernate的值。

+0

優秀點!只是我不明白爲什麼'insert'觸發器觸發兩次?! – 2017-01-03 06:41:50

+0

因爲DBMS(Oracle)獨立於Hibernate。僅僅使用Hibernate,你通常只會觸發一次觸發器,因爲Hibernate負責插入,修改和刪除記錄。在我的情況下,我需要一個觸發器來執行Hibernate的角色,以便在沒有Hibernate的情況下完成那些記錄操作。 – Julio 2017-01-07 09:23:35

相關問題