休眠异常缺少信息:非法尝试将集合与两个打开的会话相关联

Posted

技术标签:

【中文标题】休眠异常缺少信息:非法尝试将集合与两个打开的会话相关联【英文标题】:Hibernate Exception lack of info : Illegal attempt to associate a collection with two open sessions 【发布时间】:2021-05-07 10:09:59 【问题描述】:

我有一个非常关键的案例要处理这个错误。我不能共享代码,因为它很大而且很复杂。我唯一可以分享的是异常堆栈跟踪和异常所涉及的模型实体的一部分。 这是异常堆栈跟踪:

org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
at org.hibernate.collection.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:410)
at org.hibernate.event.def.OnUpdateVisitor.processCollection(OnUpdateVisitor.java:43)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:101)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:61)
at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:55)
at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:123)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:293)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:223)
at org.hibernate.event.def.DefaultUpdateEventListener.performSaveOrUpdate(DefaultUpdateEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireUpdate(SessionImpl.java:564)
at org.hibernate.impl.SessionImpl.update(SessionImpl.java:552)
at org.hibernate.impl.SessionImpl.update(SessionImpl.java:544)
at com.riskanalysis.server.dao.impl.base.DBDaoImpl.updateObject(DBDaoImpl.java:138)
at com.riskanalysis.server.business.impl.base.DBManagerImpl.saveObject(DBManagerImpl.java:96)
at com.riskanalysis.rttool.web.controller.action.control.ControlsAction.specificSave(ControlsAction.java:295)
at com.riskanalysis.web.controller.action.base.BaseAction.save(BaseAction.java:266)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:269)
at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:170)
at com.riskanalysis.web.controller.action.base.BaseAction.execute(BaseAction.java:154)
at org.springframework.web.struts.DelegatingActionProxy.execute(DelegatingActionProxy.java:110)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:425)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:228)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
at com.riskanalysis.web.controller.BaseActionServlet.doPost(BaseActionServlet.java:156)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)

这里是异常所涉及的部分代码。我说部分是因为异常涉及保存一个集合,而被保存的实体模型有3个集合,而异常并没有说明异常涉及哪个集合。

@Entity
@Table(name = "act_control")
public class Control extends BaseModel implements java.io.Serializable 
  private Long controlId;
  ...

  private Set<ControlResult> controlResults = new HashSet<ControlResult>();
  
  private Set<ControlCommunication> controlCommunications = new HashSet<ControlCommunication>();
  
  private Set<ControlAttachment> attachments =new HashSet<ControlAttachment>(0);
...

@OneToMany(mappedBy="control",fetch = FetchType.LAZY)
  public Set<ControlResult> getControlResults() 
    return controlResults;
  

  public void setControlResults(Set<ControlResult> controlResults) 
    this.controlResults = controlResults;
  
  @OneToMany(mappedBy="control",fetch = FetchType.LAZY)
  public Set<ControlCommunication> getControlCommunications() 
    return controlCommunications;
  

  public void setControlCommunications(Set<ControlCommunication> controlCommunications) 
    this.controlCommunications = controlCommunications;
  
@ManyToMany(fetch = FetchType.EAGER, mappedBy = "control")
  public Set<ControlAttachment> getAttachments() 
    return attachments;
  

  public void setAttachments(Set<ControlAttachment> attachments) 
    this.attachments = attachments;
  

在与开发团队,尤其是产品架构师分析此问题后,他注意到异常应该显示相关对象/集合的名称,并表示这种异常之前发生在另一个项目中,并且显示了确切的导致问题的对象的名称。所以他建议这种缺乏细节可能与java版本(使用JAVA 6构建的项目)或hibernate(hibernate 3)中缺少配置有关。

更多关于这个异常不是系统的,目前还不清楚它为什么以及何时发生,它仍然发生在之前并且可能发生在客户身上,这是我们不希望发生的:/

因此,如果有人知道如何在异常中获取有关相关对象或集合名称的更多信息,那将对我们非常有帮助。

谢谢和最好的问候,

【问题讨论】:

【参考方案1】:

异常已经说明了。您正在两个不受支持的 Hibernate 会话之间共享实体和集合。您必须先关闭第一个会话,然后才能使用第二个会话更新实体/集合。处理此问题的另一种方法是从第一个会话中分离实体/集合。

会话很便宜,所以通常它们应该只跨越一个事务。我不知道你的设置,但我猜你正在为整个请求共享一个会话。然后在一个服务中创建另一个会话并尝试使用该服务的会话保存数据,该会话之前由跨越整个请求的会话加载。

【讨论】:

以上是关于休眠异常缺少信息:非法尝试将集合与两个打开的会话相关联的主要内容,如果未能解决你的问题,请参考以下文章

“org.hibernate.HibernateException:非法尝试将集合与两个打开的会话相关联”即使上下文是 Thread

打开会话的休眠异常。我该如何调试呢?

Hibernate将对象保存到多个会话

注释 ConcurrentHashMap 时,在休眠中“非法尝试将非集合映射为 @OneToMany、@ManyToMany 或 @CollectionOfElements”

Android 文件提供程序非法参数异常

“非法尝试将非集合映射为 @OneToMany、@ManyToMany 或 @CollectionOfElements”