Description
We had earlier a datasource, which had no maxOpenPreparedStatements property defined. Something like this:
<bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource" init-method="createDataSource" destroy-method="close"> <property name="poolPreparedStatements" value="true" /> <property name="url" value="${datasource.url}" /> <property name="driverClassName" value="${datasource.driverClassName}" /> <property name="username" value="${datasource.username}" /> <property name="password" value="${datasource.password}" /> <property name="initialSize" value="${datasource.initialSize}" /> <property name="maxActive" value="${datasource.maxActive}" /> <property name="maxIdle" value="${datasource.maxIdle}" /> <property name="minIdle" value="${datasource.minIdle}" /> <property name="timeBetweenEvictionRunsMillis" value="${datasource.timeBetweenEvictionRunsMillis}" /> <property name="minEvictableIdleTimeMillis" value="${datasource.minEvictableIdleTimeMillis}" /> <property name="maxWait" value="${datasource.maxWait}" /> </bean>
Then we wanted to have a parameter to limit the prepared statement pool, so we added a new line for the maxOpenPreparedStatements (for compatibility reasons we added the line with a config file having '0' value which should mean unlimited according to the documentation at http://commons.apache.org/proper/commons-dbcp/configuration.html):
<bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource" init-method="createDataSource" destroy-method="close"> <property name="poolPreparedStatements" value="true" /> <property name="maxOpenPreparedStatements" value="${datasource.maxOpenPreparedStatements}" /> <property name="url" value="${datasource.url}" /> <property name="driverClassName" value="${datasource.driverClassName}" /> <property name="username" value="${datasource.username}" /> <property name="password" value="${datasource.password}" /> <property name="initialSize" value="${datasource.initialSize}" /> <property name="maxActive" value="${datasource.maxActive}" /> <property name="maxIdle" value="${datasource.maxIdle}" /> <property name="minIdle" value="${datasource.minIdle}" /> <property name="timeBetweenEvictionRunsMillis" value="${datasource.timeBetweenEvictionRunsMillis}" /> <property name="minEvictableIdleTimeMillis" value="${datasource.minEvictableIdleTimeMillis}" /> <property name="maxWait" value="${datasource.maxWait}" /> </bean>
We ended up in having the following exception:
Caused by: java.sql.SQLException: MaxOpenPreparedStatements limit reached at org.apache.commons.dbcp.PoolingConnection.prepareStatement(PoolingConnection.java:109) at org.apache.commons.dbcp.DelegatingConnection.prepareStatement(DelegatingConnection.java:281) at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.prepareStatement(PoolingDataSource.java:313) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ... ... [:1.7.0_07] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)[:1.7.0_07] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)[:1.7.0_07] at java.lang.reflect.Method.invoke(Method.java:601)[:1.7.0_07] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309) at org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.doInvoke(ServiceInvoker.java:58) at org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.invoke(ServiceInvoker.java:62) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131) at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor$1.run(ServiceTCCLInterceptor.java:47) at org.springframework.osgi.util.internal.PrivilegedUtils.executeWithCustomTCCL(PrivilegedUtils.java:124)[80:org.springframework.osgi.core:1.2.1] at org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invokePrivileged(ServiceTCCLInterceptor.java:44) at org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invoke(ServiceTCCLInterceptor.java:36) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.osgi.service.importer.support.LocalBundleContextAdvice.invoke(LocalBundleContextAdvice.java:59) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131) at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) at $Proxy69.getSpecializedSequenceProvider(Unknown Source) at ...) ... 36 more Caused by: java.util.NoSuchElementException: Pool exhausted at org.apache.commons.pool.impl.GenericKeyedObjectPool.borrowObject(GenericKeyedObjectPool.java:1143) at org.apache.commons.dbcp.PoolingConnection.prepareStatement(PoolingConnection.java:107) ... 67 more
So it turned out, that the documentation is wrong. Only negative numbers like -1 mean unlimited. 0 seems to mean limited to one item. Please correct the documentation to avoid problems of others.