The connection is closed when using Oracle UCP - oracle

I'm getting random " The connection is closed: The connection is closed" errors when using Oracle UCP, v 12.1.0.2.0. It looks like connection is marked as closed in
oracle.ucp.jdbc.proxy.JDBCConnectionProxyFactory#invoke :
if(Clock.isBefore(this.creationTS, this.m_jdbcPooledConnection.getAvailableStartTime()) || Clock.isBefore(this.creationTS, this.m_jdbcPooledConnection.getBorrowedStartTime())) {
this.m_closed = Boolean.valueOf(true);
}
The Clock.isBefore(this.creationTS, this.m_jdbcPooledConnection.getAvailableStartTime()) returns true.
Could somebody please explain what this check is for?
The getAvailableStartTime is set when connection is retured to the pool, the creationTS - is set when JDBCConnectionProxyFactory is being created and it's being created when giving connection away.
The isBefore looks like this:
public static boolean isBefore(long time1, long time2) {
return time1 < time2 - 1000L;
}
So, is the condition for the cases when connection was returned less than a second ago?
ps: tried validation query "select 1 from dual" - no effect

If Clock.isBefore(this.creationTS, this.m_jdbcPooledConnection.getAvailableStartTime()) returns true then it means that UCP has recollected the connection and made it available again. This typically happens if you turn on connection harvesting in UCP. UCP detects when a connection is borrowed but not used for too long (poorly designed application) and to avoid connection leaks it will grab the connection back and make it available in the pool. If the original thread then wakes up and attempts to use the connection it gets a connection is closed error.

Related

SingleConnectionDataSource now closing on new instance

I have a small commandline utility. My code is simple I create a SingleConnectionDataSource and pass it along till it is needed and I do
ds.getConnection()
Uptil now it was working and I would get a connection and would use it but some months back this stopped working and threw an exception
Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Connection was closed in SingleConnectionDataSource. Check that user code checks should Close() before closing Connections, or set 'suppress Close' to 'true'
Now when i create the datasource I added
((SingleConnectionDataSource)db).setSuppressClose(true);
and now it works fine ( as the exception suggested)
My question is why did it stop working or how was it working before, why would it be closed even at first user. As per the java doc it is supposed to be
Implementation of SmartDataSource that wraps a single JDBC Connection
which is not closed after use.
So I should be the one closing it to begin with at the end of the process.
So technically, I have a question of why did i get the problem that i have already solved but i don't understand when did this start coming.
Edit -- It behaves like this on SQL server only and not Oracle.
Edit2 -- Sorry, In oracle it uses a different way so it works
JdbcTemplate template = new JdbcTemplate(dataSource);
So either use SuppressClose(true) or use JdbcTemplate
We would need to know your database and application server to answer definitively, but my guess is that one or the other was closing the connection after a timeout. Why are you trying to manage the connection to begin with however? Many application servers provide a connection pool.
This is a partial answer to my own question: why would it close the connection before first use?
in SingleConnectionDatasource getConnection calls
/**
* Initialize the underlying Connection via the DriverManager.
*/
public void initConnection() throws SQLException {
if (getUrl() == null) {
throw new IllegalStateException("'url' property is required for lazily initializing a Connection");
}
synchronized (this.connectionMonitor) {
closeConnection();
this.target = getConnectionFromDriver(getUsername(), getPassword());
prepareConnection(this.target);
if (logger.isDebugEnabled()) {
logger.debug("Established shared JDBC Connection: " + this.target);
}
this.connection = (isSuppressClose() ? getCloseSuppressingConnectionProxy(this.target) : this.target);
}
}
This basically, creates a closed connection to begin with. Which makes it more intriguing why did it work in the first place. This class has been with the same initConnection() method since its inception ( as far as I can see on github).

does jdbcTemplate close resultsets?

I have a spring application where its home page fire multiple ajax calls which in turn fetch data from the DB and return back. The DB has been configured with connection pooling with minPoolSize as 50 and maxPoolSize as 100.
now when I open the home page, around 7 connections are established with the DB, which is expected as around 7 ajax calls are made and I assume all create their own connection. Now when I refresh the page, I see 7 more new connection are established (I see total 14 physical connections from db2 monitoring), which seems to be unexpected, as I assume jdbcTemplate do close the connection after the query from the first access and refresh in this case should reuse the connections ?
Now question here is does resultsets are also getting closed by jdbcTemplate along with connection close ? or Do i need to explicitly close the resultSet so that connection can be closed automatically. Opened resultSet may be a reason of connection not getting close ? Attaching the code for connection pooling configuration
<dataSource jdbcDriverRef="db2-driver" jndiName="jdbc/dashDB-Development" transactional="true" type="javax.sql.DataSource">
<properties.db2.jcc databaseName="BLUDB" id="db2-dashDB-Development-props" password="********" portNumber="*****" serverName="*********" sslConnection="false" user="*****"/>
<connectionManager id="db2-DashDB-Development-conMgr" maxPoolSize="100" minPoolSize="50" numConnectionsPerThreadLocal="2"/>
My initial theory was that the reuse of the connection will happen only when minPoolSize is reached and till that time it will always create new physical connection. HOwever I see this behavior even after reaching that limit. I refreshed my page 10 time and I see 70 physical connections. Now my only doubt is that connection are somehow are not getting close and spring is seeing those connection busy ? This may be because resultsets are not closed or some other reason ? Is it a way to say jdbctemplate not to wait for closing resultset beyond a time limit ?
Thanks
Manoj
If you look at the org.springframework.jdbc.core.JdbcTemplate.query method source code you see calls to -
JdbcUtils.closeResultSet(rs);
In the finally blocks - so yes JDBCTemplate does call rs.close
The template also closes or returns the connection to the pool

JDBC connection lifecycle for Connection Pool (Hikari) reuse

Hikari: 2.4.7
PostgreSQL JDBC driver: 9.4-1201-jdbc41
I'm trying to understand what must be done to a java.sql.Connection object for it to be available again in the
connection pool?
I've just introduced connection pooling to a multi threaded application that was
previously standing up / tearing down connections with each SQL statement.
What I have noticed, after introducing Hikari, is that as soon as I hit maximumPoolSize every attempt
thereafter to HikariDataSource.getConnection will fail due to connectionTimeout. So it seems like I'm not "releasing" this connection somehow.
The typical use of the Connection object is:
# omits Exception handling, parameter substitution, result evaluation.
PreparedStatement preparedStatement = hikariDataSource.getConnection().prepareStatement(sql);
preparedStatement.executeQuery();
preparedStatement.close();
Is there anything else that is expected to be done on this connection to get it eligible for reuse in the connection pool?
Autocommit is on. Connection.close(), unless doing something special when provided by Hikari, seemed like the exact thing I wanted to avoid.
I don't know Hikari specifically, but for every connection you take out of a connection pool, you have to return that connection when you are done with it.
Typically this is done using Connection.close() - the pool hands out a wrapper function where close() doesn't physically close the connection, only returns it.
So your code should look like this:
Connection con = hikariDataSource.getConnection();
PreparedStatement preparedStatement = con.prepareStatement(sql);
preparedStatement.executeQuery();
preparedStatement.close();
con.close(); // this returns the connection to the pool
Of course the two close() methods should be called in a finally block.

is setautocommit(true) needed after conn.commit()

Got the db connection (conn) from the pool.
Assume that autocommit is TRUE on that connection.
Now conn.setautocommit(false) has set ;
then after few statement updates and finally conn.commit()/conn.rollback() has done.
Now do i need to do explicitly code setautocommit(true) to revert to the previous conn state?
OR commit()\rollback() will set setautocommit(true) inherently ?
That depends on where you got that connection from. If you created the connection yourself, there is no need to restore the state of auto commit.
If you got it from a data source, you should restore the state to what it was because the data source might keep the connections in a pool and the next piece of code might not expect what you set.
commit() doesn't influence the value of auto commit. Enabling auto commit just makes sure that the JDBC driver calls commit() after each statement that you execute. You can still call commit() as often as you like, it just won't have any effect (except that rollback() will not always do what you want).
[EDIT] How auto commit is handled depends on your connection pool. dbcp has a config option to turn auto commit off before giving you a connection, c3p0 will roll back connections when you return then to the pool. Read the documentation for your connection pool how it works.
If you don't know which pool is used, the safe solution is to set auto commit to false whenever you get a connection and to roll back the connection if you get an exception. I suggest to write a wrapper:
public <T> T withTransaction( TxCallback<T> closure ) throws Exception {
Connection conn = getConnection();
try {
boolean autoCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
T result = closure.call(conn); // Business code
conn.commit();
conn.setAutoCommit(autoCommit);
} catch( Exception e ) {
conn.rollback();
} finally {
conn.close();
}
}
This code will correctly handle the connection for you and you don't need to worry about it anymore in your business code.
Interestingly, conn.setAutoCommit(true); implies a commit (if it's in autoCommit(false) mode, see here, but it might be clearer to people if you still break them out.
In Oracle 12c connection will be defaulted to the autocommit true. But if you set the autocommit as false, you need to reset the autocommit as true before release to the connection pool.
conn.setAutoCommit(autoCommit); should move to the finally block

Is there any way to have the JBoss connection pool reconnect to Oracle when connections go bad?

We have our JBoss and Oracle on separate servers. The connections seem to be dropped and is causing issues with JBoss. How can I have the JBoss reconnect to Oracle if the connection is bad while we figure out why the connections are being dropped in the first place?
Whilst you can use the old "select 1 from dual" trick, the downside with this is that it issues an extra query each and every time you borrow a connection from the pool. For high volumes, this is wasteful.
JBoss provides a special connection validator which should be used for Oracle:
<valid-connection-checker-class-name>
org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker
</valid-connection-checker-class-name>
This makes use of the proprietary ping() method on the Oracle JDBC Connection class, and uses the driver's underlying networking code to determine if the connection is still alive.
However, it's still wasteful to run this each and every time a connection is borrowed, so you may want to use the facility where a background thread checks the connections in the pool, and silently discards the dead ones. This is much more efficient, but means that if the connections do go dead, any attempt to use them before the background thread runs its check will fail.
See the wiki docs for how to configure the background checking (look for background-validation-millis).
There is usually a configuration option on the pool to enable a validation query to be executed on borrow. If the validation query executes successfully, the pool will return that connection. If the query does not execute successfully, the pool will create a new connection.
The JBoss Wiki documents the various attributes of the pool.
<check-valid-connection-sql>select 1 from dual</check-valid-connection-sql>
Seems like it should do the trick.
Not enough rep for a comment, so it's in a form of an answer. The 'Select 1 from dual' and skaffman's org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker method are equivalent , although the connection check does provide a level of abstraction. We had to decompile the oracle jdbc drivers for a troubleshooting exercise and Oracle's internal implementation of the ping is to perform a 'Select 'x' from dual'. Natch.
JBoss provides 2 ways to Validate connection:
- Ping based AND
- Query based
You can use as per requirement. This is scheduled by separate thread as per duration defined in datasource configuration file.
<background-validation>true</background-validation> <background-validation-minutes>1</background-validation-minutes>
Some time if you are not having right oracle driver at Jboss, you may get classcast or related error and for that connection may start dropout from connection pool. You can try creating your own ConnectionValidator class by implementing org.jboss.resource.adapter.jdbc.ValidConnectionChecker interface. This interface provides only single method 'isValidConnection()' and expecting 'NULL' in return for valid connection.
Ex:
public class OracleValidConnectionChecker implements ValidConnectionChecker, Serializable {
private Method ping;
// The timeout (apparently the timeout is ignored?)
private static Object[] params = new Object[] { new Integer(5000) };
public SQLException isValidConnection(Connection c) {
try {
Integer status = (Integer) ping.invoke(c, params);
if (status.intValue() < 0) {
return new SQLException("pingDatabase failed status=" + status);
}
}
catch (Exception e) {
log.warn("Unexpected error in pingDatabase", e);
}
// OK
return null;
}
}
A little update to #skaffman's answer. In JBoss 7 you have to use "class-name" attribute when setting valid connection checker and also package is different:
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleValidConnectionChecker" />
We've recently had some floating request handling failures caused by orphaned oracle DBMS_LOCK session locks that retained indefinitely in client-side connection pool.
So here is a solution that forces session expiry in 30 minutes but doesn't affect application's operation:
<check-valid-connection-sql>select case when 30/60/24 > sysdate-LOGON_TIME then 1 else 1/0 end
from V$SESSION where AUDSID = userenv('SESSIONID')</check-valid-connection-sql>
This may involve some slow down in process of obtaining connections from pool. Make sure to test this under load.

Resources