Queries take too long after MySQL fail-over - java

I have an application that uses MySQL fail-over via a connection url:
jdbc:mysql://172.17.0.4:3306,172.17.0.3:3306/db_name?autoReconnect=true&failOverReadOnly=false
Now when primary db is down then it should move to secondary connection and application flow should work as expected.
Now the problem happens when moving to secondary db. It takes too long to move/execute the queries, causing the flow to take much longer than expected.
I have checked already with db and there's no slow query issues. I guess it's something to do with fail-over and with checking the states. So, any idea what might be causing this issue or how to resolve this delay?
I am also using c3p0 to manage the connections pools. Already tried with initialTimeout and maxReconnects but no luck so far.
DataSource
<bean id="productionDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="description" value="integration_ds"/>
<!-- configuration pool via c3p0-->
<property name="acquireIncrement" value="${datasource.acquireIncrement}"/>
<property name="idleConnectionTestPeriod" value="${datasource.idleConnectionTestPeriod}"/>
<!-- seconds -->
<property name="maxPoolSize" value="${datasource.maxPoolSize}"/>
<property name="maxStatements" value="${datasource.maxStatements}"/>
<property name="maxStatementsPerConnection" value="${datasource.maxStatementsPerConnection}"/>
<property name="minPoolSize" value="${datasource.minPoolSize}"/>
<property name="initialPoolSize" value="${datasource.initialPoolSize}"/>
<property name="maxIdleTime" value="${datasource.maxIdleTime}"/>
<property name="acquireRetryAttempts" value="${datasource.acquireRetryAttempts}"/>
<property name="acquireRetryDelay" value="${datasource.acquireRetryDelay}"/>
<property name="breakAfterAcquireFailure" value="${datasource.breakAfterAcquireFailure}"/>
<property name="debugUnreturnedConnectionStackTraces" value="true"/>
</bean>
Properties
datasource.acquireIncrement=1
datasource.idleConnectionTestPeriod=1000
datasource.maxPoolSize=10
datasource.maxStatements=600
datasource.minPoolSize=5
datasource.initialPoolSize=5
datasource.maxIdleTime=7200
#datasource.acquireRetryAttempts=5
datasource.acquireRetryAttempts=1
#datasource.acquireRetryDelay=5000
#datasource.acquireRetryDelay=1000
datasource.acquireRetryDelay=100
datasource.breakAfterAcquireFailure=false
datasource.maxStatementsPerConnection=3
datasource.checkoutTimeout=100
DAO
private static final String findByAppIdHql = "select app from AppImpl app where app.appId = ?";
final Query query = sf.getCurrentSession().createQuery(findByAppIdHql).setString(0, appId);
query.setCacheable(true);
query.setCacheRegion("app_query_cache");
query.setCacheMode(CacheMode.NORMAL);
List<App> apps = query.list();

Related

Hibernate: why c3p0 timeout not working?

I work on web java application using hibernate, and i always get memory low errors for tons of java inactive sessions on my oracle db. i tried to closing this unused sessions with c3p0 timeout config but it's not working at all.
this is my hibernate config and my open sessions after several minutes:
(the commented code below is for when i tried using common dbcp refer to one of answers for similar questions and timeout times set to 30 seconds for test.)
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:#localhost:test</property>
<property name="hibernate.connection.username">tams_test</property>
<property name="hibernate.connection.password">test1234</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="hibernate.connection.isolation">2</property>
<property name="org.hibernate.flushMode">COMMIT</property>
<property name="hibernate.cache.use_query_cache">false</property>
<property name="hibernate.transaction.auto_close_session">true</property>
<property name="hibernate.order_updates">true</property>
<property name="hibernate.order_inserts">true</property>
<!-- <property name="hibernate.dbcp.initialSize">3</property>
<property name="hibernate.dbcp.maxIdle">50</property>
<property name="hibernate.dbcp.minIdle">0</property>
<property name="hibernate.dbcp.maxWait">180000</property>
<property name="hibernate.dbcp.maxConnLifetimeMillis">30000</property>
<property name="hibernate.dbcp.defaultQueryTimeout">1</property>-->
<property name="hibernate.c3p0.min_size">1</property>
<property name="hibernate.c3p0.max_size">150</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.timeout">30</property>
<property name="hibernate.c3p0.idle_test_period">30</property>
<property name="hibernate.c3p0.idleConnectionTestPeriod">30</property>
<property name="c3p0.testConnectionOnCheckout">true</property>
<property name="testConnectionOnCheckin">true</property>
<property name="c3p0.maxConnectionAge">30</property>
<property name="maxIdleTimeExcessConnections">30</property>
<property name="connection.provider_class">
org.hibernate.connection.C3P0ConnectionProvider
</property>
open sessions on oracle db after several minutes
I faced your problem too, and hibernate didn't want to apply my parameters of c3p0, so I changed my datasource and it completly solved my problem of inactive sessions.
Try to setup your dataSource bean like this:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/>
<property name="jdbcUrl" value="jdbc:oracle:thin:#xxxx:1521:xxx"/>
<property name="user" value="xx"/>
<property name="password" value="xxxx"/>
<property name="maxStatements" value="1000"/>
<property name="maxIdleTime" value="30"/>
<property name="maxPoolSize" value="100"/>
<property name="minPoolSize" value="10"/>
<property name="initialPoolSize" value="10"/>
<property name="idleConnectionTestPeriod" value="20"/>
</bean>

Connection pooling in spring jdbc

I have implemented spring jdbc in my project. I am just curious to know how connection pooling in handled in spring jdbc? If spring is taking care of connections, then where can I specify the max number of connections allowed for my application?
Another question is how is connection pooling handled in simple jdbc.
Please clarify.
You can use own custom datasource, like this:
<bean id="springDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
<property name="url" value="jdbc:oracle:thin:#localhost:1521:SPRING_TEST" />
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="username" value="root" />
<property name="password" value="root" />
<property name="removeAbandoned" value="true"/>
<property name="initialSize" value="20" />
<property name="maxActive" value="30" />
</bean>
//Dao class configuration in spring
<bean id="EmployeeDatabaseBean" class="com.test.EmployeeDAOImpl">
<property name="dataSource" ref="springDataSource"/>
</bean>
Official documentation
Here or here described pretty simple.

jdbc connection string with c3p0

I have jdbc configured with c3p0.
However, I am worried about possible conflicts, since some of the parameters in jdbc string and c3p0 are similar.
Here is my jdbc string:
jdbc:mysql://1.1.1.1:3306/db?useSSL=true&requireSSL=true&connectTimeout=15000&socketTimeout=30000&autoReconnect=true
We decided to include connectTimeout, socketTimeout, autoReconnect
because otherwise it took too long to switch to the replica if master crashes. ( We are using MySQL RDS Multi-AZ ).
Here are my c3p0 properties:
<property name="acquireIncrement" value="3"/>
<property name="minPoolSize" value="5"/>
<property name="maxPoolSize" value="10"/>
<property name="maxIdleTime" value="3600"/>
<!-- 1 hour -->
<property name="maxConnectionAge" value="7200"/>
<property name="maxIdleTimeExcessConnections" value="600"/>
<property name="idleConnectionTestPeriod" value="180"/>
<property name="testConnectionOnCheckin" value="true"/>
<property name="testConnectionOnCheckout" value="false"/>
Any ideas / suggestions?
Maybe someone has production-ready configuration?
Best Regards,
Maksim

JMS 112 Invalid connection using spring ds

I'm using a spring datasource and is unable to connect to Oracle AQ Queue.
Connection connection = null;
AQSession aqSess = null;
connection = ds.getConnection();
connection.setAutoCommit(false);
DataSourceUtils.getTargetConnection(connection);
Class.forName("oracle.AQ.AQOracleDriver");
aqSess = AQDriverManager.createAQSession(connection);
aqSession = aqSess;
But still get this: oracle.jms.AQjmsException: JMS-112: Connection is invalid any tips would be appreciated.
<bean id="myId" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#myIpAddress:dev"/>
<property name="username" value="user"/>
<property name="password" value="pass"/>
<property name="removeAbandoned" value="true"/>
<property name="initialSize" value="2"/>
<property name="maxIdle" value="8"/>
<property name="maxActive" value="30"/>
<property name="maxWait" value="60000"/>
</bean>
AQException: oracle.AQ.AQException: JMS-112: Connection is invalid
at oracle.AQ.AQDriverManager.createAQSession(AQDriverManager.java:193)
I fixed my problem using the following code:
OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
Recording it here as an answer in case others find this question when having a similar problem.
Oracle AQ doesn't match with BasicDataSource
useOracleDataSource instead
but if you want to use BasicDataSource:
In many application server environments the JDBC connection is wrapped
in an implementation specific class that delegates to the underlying
native JDBC connection. Oracle's AQ connection factory needs the
native Oracle connection and will throw an "oracle.jms.AQjmsException:
JMS-112: Connection is invalid" exception if the connection is wrapped
by a foreign class. To solve this problem you can specify a
NativeJdbcExtractor that can be used to unwrap the connection. Spring
provides a number of implementations to match the application server
environment. Here is an example for specifying a NativeJdbcExtractor.
<orcl:aq-jms-connection-factory id="connectionFactory"
use-local-data-source-transaction="true"
native-jdbc-extractor="dbcpNativeJdbcExtractor" 1
data-source="dataSource" />
<bean id="dbcpNativeJdbcExtractor"
class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"/>
<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<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>
https://docs.spring.io/spring-data/jdbc/old-docs/2.0.0.BUILD-SNAPSHOT/reference/html/orcl.streamsaq.html

Configure spring datasource for hibernate and #Transactional

At this moment I'm using DriverManagerDataSource with #Transactional annotation to manage transactions. But all transactions are very very slow, probably because data source open and close connection to db each time.
What data source should I use to speed up transaction?
I am using in my application combination of two approaches. the first one is c3p0 connection pooling, its almost the same solution as chkal sugested. The second approach is to use Spring lazyConnectionDataSourceProxy, which creates lazy loading proxy that loads connection only if you hit the database. This is very useful, when you have second level cache and you are only reading cached data and queries - database wont be hit, and you don't need to acquire connection (which is pretty expensive).
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- Pool properties -->
<property name="minPoolSize" value="5" />
<property name="initialPoolSize" value="10" />
<property name="maxPoolSize" value="50" />
<property name="maxStatements" value="50" />
<property name="idleConnectionTestPeriod" value="120" />
<property name="maxIdleTime" value="1200" />
</bean>
<bean name="lazyConnectionDataSourceProxy" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource" ref="dataSource" />
</bean>
DriverManagerDataSource isn't actually a connection pool and should only be used for testing. You should try BasicDataSource from Apache Commons DBCP. Something like:
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<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>

Categories