我正在使用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; ....... }
让我们看看这两种情况:
员工不存在,我尝试创建一个新员工。两种不同的情况:
这是事务处理程序:
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类中)得到的结果:
idEmployee
idAddress
org.hibernate.exception.ConstraintViolationException
简而言之,异常仅在提交过程中出现。就像这是开始提交孩子(地址)而不是父母(雇员)一样。
我究竟做错了什么?有谁能够帮助我?提前致谢。
更新。 在上面,您可以看到问题涉及的两个类的主要部分。现在,除了跟踪异常之外,这里还有调用它们的方法。它们按被调用的顺序排列。
属于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
经过几天的努力,我终于找到了问题所在,显然是解决方案。据我所知,上面显示的映射是正确的(至少,该应用程序正常运行)。唯一的问题是在数据库中,那里有一个插入序列的触发器。这样,每次我尝试插入一个雇员(及其地址)时,Hibernate都会给我两个序列号(一个用于父级,另一个用于子级),它们已正确设置。但是,在执行提交的确切时刻,Oracle给了我两个更多的序列号,但是这次设置不正确,我的意思是,外键与父级的主键不匹配。
但是,当我需要触发器时,我必须再执行一个步骤:必须修改这些触发器,以便它们检查该:new.ID值是否是NULL。如果是,则意味着该触发器已从外部Hibernate(即另一个应用程序)触发,因此我从序列中获取nextval,否则我将保留来自Hibernate的值。
:new.ID
NULL