Uploaded image for project: 'Spring Web Flow'
  1. Spring Web Flow
  2. SWF-1525

Database connection leak using JPA and loading lazy initialized entities using WebFlow's presistence context

    Details

      Description

      When entities have lazy-initialized relations and they are loaded using WebFlow's persistence context (without transaction) then database connection is not closed but at the same time is not reused later - i.e. it's just lost. This problem initially appeared in working project and I was able to reproduce it in small test project (attached).

      About sample.
      This project is based on booking-faces example. The main changes were done in webflow-config.xml (added jpaFlowExecutionListener), data-access-config.xml (using MySQL and tomcat-jdbc connection pool (original application with this problem used DBCP pool)) and main-flow.xml (greatly simplified). Also a new entity, Suite, was added as one-to-many relation to Hotel in order to add lazy initialization. On start of the main flow a Hotel instance is loaded using transaction method from service and then its lazy relation is initialized using WebFlow's entity manager.

      How to reproduce problem.
      Deploy and start application (also start mysql server with booking_faces database). On start page click "Start your Spring Travel experience". That's it, one connection is leaked (this was checked using a heap dump). Now click on top Spring logo at the top to return to main page. Do the same two more times. Now when you'll click on start link for the forth time (maxActive connections for the pool is set to 3) an exception will pop up:

       
      java.sql.SQLException: [http-8080-2] Timeout: Pool empty. Unable to fetch a connection in 30 seconds, none available[size:3; busy:3; idle:0; lastwait:30000].
      	org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:638)
      	org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:179)
      	org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:124)
      	org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider.getConnection(InjectedDataSourceConnectionProvider.java:71)
      	org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
      	org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
      	org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:142)
      	org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:85)
      	org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1463)
      	org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:60)
      	org.springframework.orm.jpa.DefaultJpaDialect.beginTransaction(DefaultJpaDialect.java:70)
      	org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:57)
      	org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:332)
      	org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
      	org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
      	org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
      	org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
      	org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
      	$Proxy30.findHotelById(Unknown Source)
      	localhost.MyForm.loadHotel(MyForm.java:16)
      	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      	java.lang.reflect.Method.invoke(Method.java:597)
      	org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute(ReflectiveMethodExecutor.java:69)
      	org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:83)
      	org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:57)
      	org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:102)
      	org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:97)
      	org.springframework.binding.expression.spel.SpringELExpression.getValue(SpringELExpression.java:84)
      	org.springframework.webflow.action.EvaluateAction.doExecute(EvaluateAction.java:75)
      	org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188)
      	org.springframework.webflow.execution.AnnotatedAction.execute(AnnotatedAction.java:145)
      	org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51)
      	org.springframework.webflow.engine.ActionList.execute(ActionList.java:155)
      	org.springframework.webflow.engine.Flow.start(Flow.java:534)
      	org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:366)
      	org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:222)
      	org.springframework.webflow.executor.FlowExecutorImpl.launchExecution(FlowExecutorImpl.java:140)
      	org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:193)
      	org.springframework.faces.webflow.JsfFlowHandlerAdapter.handle(JsfFlowHandlerAdapter.java:48)
      	org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
      	org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
      	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
      	org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
      	javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
      	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
      	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:343)
      	org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
      	org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
      	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
      	org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
      	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
      	org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
      	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
      	org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78)
      	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
      	org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
      	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
      	org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
      	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
      	org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:177)
      	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
      	org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:188)
      	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
      	org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
      	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
      	org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
      	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
      	org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:149)
      	org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
      	org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
      	org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
      	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
      

      This issue is basically the same as SWF-1210 (was not sure whether I should just comment there?). Rossen Stoyanchev commented: JPA does not provide a configurable connection release mode and providers should always eagerly release JDBC connections. Indeed, setting hibernate.connection.release_mode to after_statement resolves described problem. Is this a supposed solution? If it is then it should probably be documented, because Hibernate's documentation suggests using after_transaction for non-JTA environments.

        Attachments

          Activity

            People

            • Assignee:
              rstoya05-aop Rossen Stoyanchev
              Reporter:
              yozh-tema Artem Karpenko
            • Votes:
              7 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

              • Created:
                Updated: