看了很多关于inverse的文章,理解得也不是很透彻,这次做了这个项目,遇到这方面问题,就总结了一样关于inverse的配置,
1.关系parent和children的例子也已经说了怎么去配置一对多的关系,这个例子已经说明了在set端设置inverse=true,原因很简单,child长大了,不需要什么事情都要parent带到
其实在我看来,inverse=true实际上是去解放了one那一方,在这儿就是指parent对象,他不需要在每次更新的时候,都把children都加载出来。像在下面的代码中,不会有什么问题,应该都在一个session中完成的
ParentManager manager=(ParentManager) getBean("parentManager");
Parent parent=manager.getParent("pppp");
parent.setName("bob");manager.save(parent);
所以不会觉得有什么问题。但是在WEB应用的三层结构中,通常要把模型传递到表现层中,完成更新操作,那这个时候inverse=true的优势就明显了,他可以不用考虑Children就完成自身的更新
2.当inverse=false会发生什么?
那天也是无意注意到这个问题,突然把系统的所有inverse都设置成了false
当在插入一个新的对象的时候,不会出现什么问题。但是在更新父对象的时候,却发生了我不想看到的,Customer和Order是一对多的关系
Hibernate: update customer.name=?..........where customerName=? and version=?
Hibernate: update orders set customer=null where customer=?
在更新了customer信息后,同时把订单中该用户的用户置为null,换句话说就是断了两者之间的联系。再看看代码
CustomerForm customerForm = (CustomerForm) form;
Customer customer = new Customer();
convertObject(customerForm, customer);
CustomerManager manager = (CustomerManager) getBean("customerManager");
manage.save(customer);
customerForm是通过struts的form理到来自表单的数据。最后通过业务层的代码调用Hibernate的saveOrUpdate()方法进行保存。这个时候我发现我并未去加载和customer关系的order,
然后我修改了代码,试着把所有的该customer的order都提出来,并在保存前调用了
customer .setOrder(order);
结果发生异常
org.springframework.orm.hibernate3.HibernateSystemException: a different object with the same identifier value was already associated with the session: [com.us.ebuy.model.Customer#123]; nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.us.ebuy.model.Customer#123]
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.us.ebuy.model.Customer#123]
at org.hibernate.engine.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:629)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:258)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:216)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:531)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:519)
at org.springframework.orm.hibernate3.HibernateTemplate$18.doInHibernate(HibernateTemplate.java:690)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:365)
at org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:687)
at com.us.ebuy.dao.hibernate.BaseDAOHibernate.saveObject(BaseDAOHibernate.java:55)
at com.us.ebuy.users.dao.hibernate.CustomerDAOHibernate.saveCustomer(CustomerDAOHibernate.java:64)
at com.us.ebuy.users.service.impl.CustomerManagerImpl.saveCustomer(CustomerManagerImpl.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:335)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:181)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:148)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)
at $Proxy2.saveCustomer(Unknown Source)
at com.us.ebuy.users.action.CustomerAction.save(CustomerAction.java:133)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:274)
at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:194)
at com.us.ebuy.action.BaseAction.execute(BaseAction.java:143)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:419)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:224)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:174)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:75)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
at java.lang.Thread.run(Thread.java:595)
可以看出,在更新的时候,他执行了插入操作,才会认为有重复的key,后来我想到了使用hibernate的merge方法,通过合作,才能完成customer的更新操作,但这这种更新方法显然是我们不愿意看到的。后来通过检测配置文件才发现,set 元素的inverse=false,最后我想是这儿的原因,改为false后,还是通过saveOrUpdate()方法更新对象,问题解决了。
通过上面的问题,可以更进一步的清楚了,Hibernate在对对待持久化的对象和游离状态的对象是不一样的,上述问题通常都是发生在处理游离状态的对象时候,而在三层结构中,我们会经常处理这种问题的,看来是要重新理解对象的状态问题。