views:

481

answers:

2

I'm starting to lose faith in Hibernate. It has caused me nothing but weird problems throughout the last few days.
Upon deleting an entity from the database I get the following exception:

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)

I've dug deep and tried numerous solutions from the hibernate forum, but still I don't know what's going on and where the sessions are opened. The conditions under which this problem occurs:

  • first: OpenSessionInViewFilter - I've asked about it here. Everything seemed to work fine, but the deleting stopped all of a sudden the following day and all I've done is - I've added a non-connected class to a non-connected package.

    hibernateFilter org.springframework.orm.hibernate3.support.OpenSessionInViewFilter singleSession false sessionFactoryBeanName sessionFactory hibernateFilter *

  • second: three-tier architecture. Here are the classes and the JSF page:


@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());
 }

}

finally the webpage:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<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"&gt; 
 <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>

`

Please help me resolve my problem. It looks as though I've gotten my share of each and every common pitfall of Hibernate. Please provide a thorough solution, because we can safely assume that I won't grasp any mild suggestions. Consider me a n00b thrown into an advanced project.

A: 

I see your service class does not have @Transactional annotation..how are you managing transactions?

daedlus
A: 

Take a look at the HibernateTemplate chapter in the Spring documentation. Take a look at implementing a callback approach to access the session.

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);
}

If the above is not what you are looking for you can still do a traditional approach as mentioned further down in the Spring documentation. In this approach don't use the HibernateTemplate to delete the object but use the Session from the HibernateDaoSupport to handle the delete.

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