Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring/Hibernate @Transactional - Session closing before it should

I can't figure out why, but the Hibernate session is closing before it should, so I can't fetch lazily loaded lists.

In the logs, it's showing that the session closes immediately after hibernateTemplate.findByNamedParam() inside the DAO.

When I run my web app, I get the following error:

Mar 29, 2011 3:13:21 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [Spring MVC Dispatcher Servlet] in context with path [/apps] threw exception [Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.communitydriven.apps.entities.Project.tags, no session or session was closed] with root cause
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.communitydriven.apps.entities.Project.tags, no session or session was closed
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
    at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365)
    at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
    at org.hibernate.collection.PersistentBag.iterator(PersistentBag.java:272)
    at com.communitydriven.apps.managers.ProjectManager.getProject(ProjectManager.java:98)
    at com.communitydriven.apps.controllers.ProjectController.getViewProject(ProjectController.java:86)
    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 org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:498)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:394)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:619)

My DAO:

@Repository
public class ProjectDao implements IProjectDao {

    private HibernateTemplate hibernateTemplate;

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }

    ...

    /**
     * {@inheritDoc}
     */
    @Override
    public Project getProject(Project project) {
        // Validate required parameters
        if ( (project.getId() == null) ) {
            throw new NullPointerException("Missing required parameter: " + 
                    project.toString());
        }

        // Parameters
        List<String> paramNames = new ArrayList<String>();
        List<Object> values = new ArrayList<Object>();

        // Construct HQL
        StringBuffer hql = new StringBuffer();
        hql.append("from Project p ");

        boolean whereUsed = false; // track of "where" clause has been used

        // Filter by Id
        if (project.getId() != null) {
            whereUsed = DaoUtils.appendFilter(whereUsed, hql);
            hql.append("p.id = :id ");
            paramNames.add("id");
            values.add(project.getId());
        }

        // Get list of matching projects
        @SuppressWarnings("unchecked")
        List<Project> projects = 
            hibernateTemplate.findByNamedParam(
                    hql.toString(),
                    paramNames.toArray(new String[paramNames.size()]), 
                    values.toArray());

        // Get unique result
        Project projectResult = DataAccessUtils.uniqueResult(projects);

        return projectResult;
    }
}

My Manager:

@Component
public class ProjectManager implements IProjectManager {

    @Autowired
    private IProjectDao projectDao;

    ...


    /**
     * {@inheritDoc}
     */
    @Transactional
    @Override
    public ProjectMO getProject(Long projectId) {
        Project project = new Project();
        project.setId(projectId);
        project = projectDao.getProject(project);

        ProjectMO projectMO = new ProjectMO();
        projectMO.setId(project.getId());
        projectMO.setName(project.getName());
        projectMO.setDescription(project.getDescription());

        StringBuffer tags = new StringBuffer();
        final String DELIMITER = ", ";
        for (Tag tag : project.getTags()) {
            tags.append(tag.getName() + DELIMITER);
        }
        projectMO.setTags(tags.toString());

        return projectMO;
    }
}

The Entity:

@Entity
@Table
public class Project {
    private Long id;
    private String name;
    private String description;
    private User submittedBy;
    private List<Tag> tags;

    public String toString() {
        final String DELIMITER = ", ";
        StringBuffer sb = new StringBuffer();

        sb.append(getClass().getName() + ": [");
        sb.append("id: " + id).append(DELIMITER);
        sb.append("name: " + name).append(DELIMITER);
        sb.append("description: " + description).append("]");

        return sb.toString();
    }

    // GETTERS AND SETTERS //

    @Id
    @Column
    @GeneratedValue
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    @Column
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Column
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    @OneToOne
    @JoinColumn
    public User getSubmittedBy() {
        return submittedBy;
    }

    public void setSubmittedBy(User submittedBy) {
        this.submittedBy = submittedBy;
    }

    @ManyToMany
    @JoinTable(name="Projects_Tags", 
            joinColumns={@JoinColumn(name="project_id")}, 
            inverseJoinColumns={@JoinColumn(name="tag_id")})
    public List<Tag> getTags() {
        return tags;
    }

    public void setTags(List<Tag> tags) {
        this.tags = tags;
    }
}

My Database context:

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="
 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd 
 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <context:property-placeholder location="classpath:database.properties"/>

    <bean id="dataSource" 
             class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <bean id="sessionFactory" 
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="hibernateProperties">
            <value>
                hibernate.dialect=org.hibernate.dialect.MySQLDialect
                hibernate.hbm2ddl.auto=update
            </value>
        </property>
        <property name="packagesToScan" value="com.communitydriven.apps.entities" />
    </bean>

    <tx:annotation-driven />

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>

</beans>
like image 590
Corey Avatar asked Mar 29 '11 22:03

Corey


People also ask

Does @transactional close session?

@Transactional helps you to extend scope of Session . Session is open first time when getCurrentSession() is executed and it is closed when transaction ends and it is flushed before transaction commits.

Is it necessary to close Hibernate session?

Hibernate SessionFactory openSession() method always opens a new session. We should close this session object once we are done with all the database operations.

What happens if Hibernate session is not closed?

When you don't close your Hibernate sessions and therefore do not release JDBC connections, you have what is typically called Connection leak. So, after a number of requests (depending on the size of your connection pool) the server will not be able to acquire a connection to respond your request.

How does @transactional works in Spring?

So when you annotate a method with @Transactional , Spring dynamically creates a proxy that implements the same interface(s) as the class you're annotating. And when clients make calls into your object, the calls are intercepted and the behaviors injected via the proxy mechanism.


1 Answers

Have you set up OpenSessionInViewFilter?

like image 152
Nilesh Avatar answered Oct 11 '22 11:10

Nilesh