org.hibernate.HibernateException:非法尝试将集合与两个打开的会话相关联

时间:2010-06-21 00:07:13

标签: spring hibernate jsf

从数据库中删除实体后,我得到以下异常:

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.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:101)
 at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:52)
 at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:767)
 at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:745)
 at org.springframework.orm.hibernate3.HibernateTemplate$25.doInHibernate(HibernateTemplate.java:790)
 at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:372)
 at org.springframework.orm.hibernate3.HibernateTemplate.delete(HibernateTemplate.java:784)
 at org.springframework.orm.hibernate3.HibernateTemplate.delete(HibernateTemplate.java:780)
 at pl.edu.agh.adam.core.projects.dao.TagDAO.delete(TagDAO.java:98)
 at pl.edu.agh.adam.core.projects.ProjectService.deleteTag(ProjectService.java:109)
 at pl.edu.agh.adam.core.projects.web.TagPresenter.deleteTag(TagPresenter.java:97)
 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:597)
 at com.sun.el.parser.AstValue.invoke(AstValue.java:234)
 at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:297)
 at org.apache.myfaces.view.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:83)
 at javax.faces.component._MethodExpressionToMethodBinding.invoke(_MethodExpressionToMethodBinding.java:88)
 at org.apache.myfaces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:100)
 at javax.faces.component.UICommand.broadcast(UICommand.java:120)
 at javax.faces.component.UIData.broadcast(UIData.java:708)
 at javax.faces.component.UIViewRoot._broadcastAll(UIViewRoot.java:890)
 at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:234)
 at javax.faces.component.UIViewRoot._process(UIViewRoot.java:1202)
 at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:623)
 at org.apache.myfaces.lifecycle.InvokeApplicationExecutor.execute(InvokeApplicationExecutor.java:35)
 at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:143)
 at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:93)
 at javax.faces.webapp.FacesServlet.service(FacesServlet.java:189)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
 at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:79)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
 at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
 at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
 at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
 at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
 at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
 at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
 at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
 at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
 at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
 at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
 at java.lang.Thread.run(Thread.java:619)

我已深入挖掘并尝试了来自hibernate论坛的众多解决方案,但我仍然不知道发生了什么以及会话的开放位置。出现此问题的条件:

首先:OpenSessionInViewFilter - 我在这里问过这件事。一切似乎工作正常,但第二天突然停止了删除,我所做的就是 - 我已经为非连接包添加了一个非连接类。

  <!-- Hibernate OpenSession Filter -->
  <filter>
   <filter-name>hibernateFilter</filter-name>
   <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
   <init-param>
    <param-name>singleSession</param-name>
    <param-value>false</param-value>
   </init-param>
   <init-param>
    <param-name>sessionFactoryBeanName</param-name>
    <param-value>sessionFactory</param-value>
   </init-param>
   </filter>
  <filter-mapping>
    <filter-name>hibernateFilter</filter-name>
   <url-pattern>*</url-pattern>
  </filter-mapping>

第二:三层架构。以下是类和JSF页面:

@Entity
@Table(name = "tag")
public class Tag implements Serializable {
private static final long serialVersionUID = 1L;
@ManyToMany(mappedBy = "tags", targetEntity = Project.class)
List<Project> projects = new ArrayList<Project>();
@Transient
public static final String PROP_ID = "id";
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "tag_id")
private Long id;
@Transient
public static final String PROP_NAME = "name";
@Column(name = "name", length = 25, unique = true)
private String name;
}

public class TagDAO extends HibernateDaoSupport implements ITagDAO {

@Override
public void create(Tag tag) {
  getHibernateTemplate().save(tag);
}

@Override
public Tag getTag(String name){
  Tag group = null;

  DetachedCriteria criteria = DetachedCriteria.forClass(Tag.class);
  criteria.add(Restrictions.eq("name", name));
  List<Tag> tags = getHibernateTemplate().findByCriteria(criteria);
  if ((tags != null) && (tags.size() > 0)) {
    group = (Tag)tags.get(0);
  }
  return group;
}

@Override
public Tag getTag(Long id){
Tag group = null;
List<Tag> groups = getHibernateTemplate().find(
 "from Tag where id = ?", id);
if ((groups != null) && (groups.size() > 0)) {
group = (Tag)groups.get(0);
}
return group;
}

@Override
public List<Tag> getTags(){
List<Tag> ret = getHibernateTemplate().find("from Tag");
System.out.println("Dao got "+ret.size()+" tags");
return ret;
}

@Override
public Integer getTagCount() {
DetachedCriteria criteria = DetachedCriteria.forClass(Tag.class);
criteria.setProjection(Projections.rowCount());
return (Integer)(getHibernateTemplate().findByCriteria(criteria).get(0));
}

@Override
public void delete(Tag group) {
getHibernateTemplate().delete(group);

}

@Override
public void update(Tag group) {

getHibernateTemplate().update(group);

}

@Override
public List<Tag> getTags(Integer first, Integer resultsPerPage,
String order, Boolean asc) {

DetachedCriteria criteria = DetachedCriteria.forClass(Tag.class);
if (asc){
criteria.addOrder(Order.asc(order));
}else{
criteria.addOrder(Order.desc(order));
} 
return (List<Tag>)getHibernateTemplate().findByCriteria(criteria, first, resultsPerPage);
}
}

public class ProjectService implements IProjectService {

// Beans used by this service.
private IProjectDAO projectDao;
private ITagDAO tagDao;

@Override
public void createProject(Project project) throws AlreadyExistsException {
 if (projectDao.getProject(project.getName()) != null) {
  throw new AlreadyExistsException();
 }
 projectDao.addProject(project);
}

@Override
public List<Project> getProjects(Integer first, Integer howMany, String order,
  boolean asc) {
 return projectDao.getProjects(first, howMany, order, asc);
} 

@Override
public Integer getProjectCount(){
 return projectDao.getProjectCount();
}

@Override
public List<Project> getProjects() {
 return projectDao.getAllProjects();
}

@Override
public void deleteProject(Long id) {
 projectDao.removeProject(id);
}

@Override
public List<Tag> getTags() {
 return tagDao.getTags();
}

@Override
public Tag getTag(String name){
 return tagDao.getTag(name);
}
@Override
public void createTag(Tag tag) throws AlreadyExistsException {
 if (tagDao.getTag(tag.getName()) != null) {
  throw new AlreadyExistsException();
 }
 tagDao.create(tag);
}
@Override
public void deleteTag(Long id) {
  tagDao.delete(tagDao.getTag(id));
}
@Override
public void updateTag(Tag tag) {
tagDao.update(tag);

}
}

@ManagedBean(name = "tagPresenter")
@RequestScoped
public class TagPresenter {

 private List<Tag> tags;
 private IProjectService projectService;
 private Tag tag;


 public void setTag(Tag tag) {
  this.tag= tag;
 }
 public Tag getTag() {
  return tag;
 }

 public TagPresenter() {
  projectService = (IProjectService)ServiceFinder.getInstance()
   .findBean("projectService");
  tags = projectService.getTags();
 }

 private void refresh() {
  tags = projectService.getTags();
 }

 public List<Tag> getTags() {
  refresh();
  return tags;
 }

 public void deleteTag() {
  projectService.deleteTag(tag.getId());
 }

}

最后是网页:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"     xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.prime.com.tr/ui"> 
 <ui:composition template="/templates/template.xhtml">
  <ui:define name="head">
   <title>Tags</title>
   <link rel="stylesheet" type="text/css" href="#{facesContext.externalContext.requestContextPath}/styles/style.css"/>
  </ui:define>
  <ui:define name="content">
  <h:form name="commandForm">
  <p:dataTable var="tag" name="tagsList" value="${tagPresenter.tags}" paginator="true" rows="10"  >
    <p:column sortBy="#{tag.id}">
      <f:facet name="header">
       <h:outputText value="Id" />
      </f:facet>
       <h:outputText value="#{tag.id}" />
     </p:column>
     <p:column sortBy="#{tag.name}">
      <f:facet name="header">
       <h:outputText value="Name" />
      </f:facet>
       <h:outputText value="#{tag.name}" />
     </p:column>
      <p:column>
       <h:commandLink action="#{tagDisplayer.showTag}" value="Modify">
         <f:setPropertyActionListener target="#{tagDisplayer.tag}" value="#{tag}"/>
       </h:commandLink>
       <h:commandLink action="#{tagPresenter.deleteTag}" value="Delete">
        <f:setPropertyActionListener target="#{tagPresenter.tag}" value="#{tag}"/>
       </h:commandLink>
     </p:column>
    </p:dataTable>
    </h:form>
    <p:messages id="deletingError" showDetail="true"/>
  </ui:define>
 </ui:composition>
    </html>

这个问题是如何引起的?如何解决?

3 个答案:

答案 0 :(得分:2)

对此的修复差异很大;它可能是由

等问题引起的
  • 框架配置中的错误会话处理
  • 错误的级联设置,不正确的持久性设置
  • 忘记了存储在@ManyToOne数据库关系中的Collection的初始化。

在浪费时间之前,请务必在映射/休眠配置中彻底检查这些情况。 :d

答案 1 :(得分:0)

查看Spring文档中的HibernateTemplate chapter。看一下实现回调方法来访问会话。

public void delete(final Tag group) throws Exception {
    HibernateCallback callback = new HibernateCallback() {
        public Object doInHibernate(Session session) throws HibernateException, SQLException {
            Object groupObj = session.load(Tag.class, group.getId());
            session.delete(groupObj);
            return null;
        }
    };
    getHibernateTemplate().execute(callback);
}

如果上述内容不符合您的要求,您仍然可以按照Spring文档中提到的further down进行传统方法。在这种方法中,不要使用HibernateTemplate删除对象,而是使用HibernateDaoSupport中的Session来处理删除。

public void delete(Tag group) throws Exception {
    Session session = getSession(false);
    Object groupObj = session.load(Tag.class, group.getId());
    session.delete(groupObj);
}

答案 2 :(得分:0)

这可能是因为调用session.disconnect()而不是session.close()