pooled connection + validation query + SQL_CALC_FOUND_ROWS - spring

I have the problem that my web application running on tomcat often drops the following exception:
java.sql.SQLException: Connection already closed
So I want to validate the connection before getting it from the pool by the following config:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/database" />
<property name="username" value="user" />
<property name="password" value="pass" />
<property name="validationQuery" value="SELECT 1"/>
<property name="testOnReturn" value="false"/>
<property name="testOnBorrow" value="true"/>
<property name="testWhileIdle" value="false"/>
<property name="maxActive" value="30" />
<property name="maxIdle" value="15" />
<property name="minIdle" value="5"/>
<property name="poolPreparedStatements" value="true"/>
<property name="connectionProperties"
value="useUnicode=true;characterEncoding=UTF-8;profileSQL=true;logger=custom.MysqlLogger;" />
</bean>
when sending the following 2 queries with spring jdbcTemplate:
SELECT SQL_CALC_FOUND_ROWS col1, col2, col3 AS foo FROM table HAVING foo = 'bar' LIMIT 0, 10;
SELECT FOUND_ROWS();
The "SELECT FOUND_ROWS()" query always returns 1 because the validation query is executed in between ("SELECT 1").
Does someone know a way to solve this problem without using COUNT in a second query???

Are both your queries in the same transaction?

Related

Connection has already been closed.; nested exception is java.sql.SQLException: Connection has already been closed

Tomcat 8
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
<property name="initialSize" value="10" />
<property name="maxActive" value="200" />
<property name="minIdle" value="10" />
<property name="maxIdle" value="50" />
<property name="maxWait" value="50000" />
<property name="fairQueue" value="true" />
<property name="logAbandoned" value="true" />
<property name="removeAbandoned" value="true" />
<property name="testOnBorrow" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="validationQuery" value="${database.validationQuery}" />
</bean>
App is running on tomcat 8 and starts giving the error after 15 20 mins
SQL state [null]; error code [0]; Connection has already been closed.; nested exception is java.sql.SQLException: Connection has already been closed.
at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1542)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:667)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:713)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:738)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:794)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:209)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForList(NamedParameterJdbcTemplate.java:303)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForList(NamedParameterJdbcTemplate.java:310)
Increase the value of removeAbandonedTimeOut in tomcat-resources.xml so that it is set to the longest running query the application may have.
removed this <property name="removeAbandoned" value="true" /> after change app is working fine

Spring JDBC Extensions, Oracle AQ, ClassCastException on listening to queue

(I hope this below makes sense, I had a bit of a struggle with formatting).
We have an application (currently being refreshed from technology of circa 2005) whose owners require the use of Oracle AQ for message handling.
We are using the Spring JDBC extensions, and when the application begins to listen to the queue it gets a ClassCastException saying "X cannot be cast to oracle.jdbc.internal.OracleConnection".
Where X is either a WrappedConnectionJDK7 from jboss when we use a datasource defined in Wildfly e.g.
<bean id="dataSource-supsrep"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:XE" />
<property name="username" value="...." />
<property name="password" value="...." />
</bean>
or X is a PoolGuardConnectionWrapper from commons.dbcp when we define the datasource like this:
<bean id="dataSource-supsrep"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:XE" />
<property name="username" value="...." />
<property name="password" value="...." />
</bean>
Message Listener bean is defined like this :
<bean id="messageListener" class="xxx.report.dispatch.DispatchMDB" />
Message Listener container bean is like this :
<bean id="reportProcessorXslfoHigh"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="sessionTransacted" value="true" />
<property name="connectionFactory" ref="AQconnectionFactory" />
<property name="destinationName" value="Q1_XSLFO_HIGH" />
<property name="messageListener" ref="messageListener" />
<property name="transactionManager" ref="transactionManager" />
<property name="concurrentConsumers" value="1" />
<property name="maxConcurrentConsumers" value="1" />
<property name="receiveTimeout" value="30000" />
<property name="idleTaskExecutionLimit" value="30" />
<property name="idleConsumerLimit" value="1" />
</bean>
The connection factory is like this :
<orcl:aq-jms-connection-factory id="AQconnectionFactory"
data-source="dataSource-supsrep" native-jdbc- extractor="oracleNativeJdbcExtractor" />
and it uses a Native JDBC Extractor :
<bean id="oracleNativeJdbcExtractor"
class="org.springframework.jdbc.support
.nativejdbc.OracleJdbc4NativeJdbcExtractor" />
So my question is - can this be overcome by Spring configuration details - or is there another way round it? Clearly the underlying connection is needed but after 3 days of research I cannot see how it can be done.
Any clues gratefully received !
Thanks,
John

Spring integration jdbc message store performance

I was using the SimpleMessageStore ( memory ) as the default Store for an Aggregator, but as i need
persistent store, i started using a jdbc solution backed up by Mysql 5.5
But i'm really concerned about its performance, as using a PerfTest ( databene's contiperf ), memory store achieved up to 6000 messages/sec, whereas using mysql ( or redis, or mongo ), i can't achieve more than 15-20 messages/sec.
<int:aggregator id="XDRAggegator"
input-channel="mqChannel"
output-channel="publishChannel"
message-store="jdbc-messageStore"
....
<bean id="reaper" class="org.springframework.integration.store.MessageGroupStoreReaper">
<property name="messageGroupStore" ref="jdbc-messageStore"/>
<property name="timeout" value="${msg.timeout}"/>
</bean>
<task:scheduler id="taskScheduler"/>
<task:scheduled-tasks scheduler="taskScheduler">
<task:scheduled ref="reaper" method="run" fixed-rate="${reaper.rate}"/>
</task:scheduled-tasks>
<task:executor id="taskExecutor" pool-size="1"/>
<task:annotation-driven executor="taskExecutor" scheduler="taskScheduler"/>
<int-jdbc:message-store id="jdbc-messageStore" data-source="dataSource" />
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" >
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://${database.host}:3306/XDR?autoReconnect=true&cachePrepStmts=true&prepStmtCacheSize=50" />
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="idleConnectionTestPeriodInMinutes" value="1"/>
<property name="idleMaxAgeInMinutes" value="2"/>
<property name="connectionTimeoutInMs" value="1000" />
<property name="maxConnectionsPerPartition" value="10"/>
<property name="minConnectionsPerPartition" value="4"/>
<property name="partitionCount" value="4"/>
<property name="acquireIncrement" value="2"/>
<property name="statementsCacheSize" value="10"/>
<property name="closeConnectionWatch" value="false"/>
</bean>
Am i missing something ?
I'm using default schema that comes into spring-integration-jdbc library.

Can I use multiple C3P0 datasources for DB instance?

I was wondering if I can run multiple c3p0 datasources for one DB, something like:
<bean id="dataSource1" class = "com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${db.driverClassName}"/>
<property name="jdbcUrl" value="${db.url}/schema1"/>
<property name="user" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="acquireIncrement" value="1" />
<property name="idleConnectionTestPeriod" value="100"/>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="50" />
<property name="maxIdleTime" value="1800" />
</bean>
<bean id="dataSource2" class = "com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${db.driverClassName}"/>
<property name="jdbcUrl" value="${db.url}/schema2"/>
<property name="user" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="acquireIncrement" value="1" />
<property name="idleConnectionTestPeriod" value="100"/>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="50" />
<property name="maxIdleTime" value="1800" />
</bean>
They will be used by difference persistence services.
Thanks.
That's absolutely fine. You'll run into some configuration issues like:
autowiring DataSource by type won't work
#Transactional/declarative transactions will work only against one, selected DataSource. Alternatively you'll have to manually tell which transaction manager you want to use (thus you'll need two transaction managers as well: transactionManager1 and transactionManager2):
#Transactional("transactionalManager2")
Besides, there's nothing wrong with this configuration. Actually it's a pretty good idea (+1): if some layers/components of your application saturate the pool, others can still operate.
The only thing I recommend is to use lesser known abstract/parent bean declarations to avoid repetition:
<bean id="dataSource" abstract="true" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${db.driverClassName}"/>
<property name="user" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="acquireIncrement" value="1" />
<property name="idleConnectionTestPeriod" value="100"/>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="50" />
<property name="maxIdleTime" value="1800" />
</bean>
<bean id="dataSource1" parent="dataSource">
<property name="jdbcUrl" value="${db.url}/schema1"/>
</bean>
<bean id="dataSource2" parent="dataSource">
<property name="jdbcUrl" value="${db.url}/schema2"/>
</bean>
See also:
What is meant by abstract="true" in spring?

Updating a row by rowid in oracle using spring-jdbc

I have a weird problem updating a row by rowid in oracle using spring-jdbc.
The problem is that everything is ok but for some rowids the update will never be done and
application is frozen.
I changed spring log level to DEBUG to see what's happening but nothing's strange and spring log is exactly as successful updates.
I tried to execute the same sql in plsql and the update was executed successfully.
spring version is 3.1.1.RELEASE
oracle version is 11.1.0.6.0
body of update method in dao is:
String sql=
"UPDATE "+schema+".MSG m SET m.STATE="+state+" WHERE ROWID='"+msg.getRowId()+"'";
getJdbcTemplate().update(sql);
dao bean:
<bean id="messageDao" class="com.foo.dao.springjdbc.MessageDaoSpringJdbcImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
jdbcTemplate:
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
data source:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#${db.ip}:${db.port}:${db.sid}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="validationQuery" value="select 1 from dual"/>
<property name="testOnBorrow" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="5000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="maxActive" value="1"/>
<property name="maxIdle" value="3"/>
</bean>
any idea?

Resources