4747 * @author Steve Ebersole
4848 */
4949public class DriverManagerConnectionProviderImpl
50- implements ConnectionProvider , Configurable , Stoppable , ServiceRegistryAwareService {
50+ implements ConnectionProvider , Configurable , Stoppable , ServiceRegistryAwareService , ConnectionValidator {
5151
5252 private static final ConnectionPoolingLogger log = ConnectionPoolingLogger .CONNECTIONS_LOGGER ;
5353
@@ -94,7 +94,7 @@ private PooledConnections buildPool(Map configurationValues, ServiceRegistryImpl
9494 pooledConnectionBuilder .initialSize ( initialSize );
9595 pooledConnectionBuilder .minSize ( minSize );
9696 pooledConnectionBuilder .maxSize ( maxSize );
97-
97+ pooledConnectionBuilder . validator ( this );
9898 return pooledConnectionBuilder .build ();
9999 }
100100
@@ -205,13 +205,20 @@ public <T> T unwrap(Class<T> unwrapType) {
205205 }
206206 }
207207
208+ protected void validateConnectionsReturned () {
209+ int allocationCount = state .pool .allConnections .size () - state .pool .availableConnections .size ();
210+ if ( allocationCount != 0 ) {
211+ log .error ( "Connection leak detected: there are " + allocationCount + " unclosed connections!" );
212+ }
213+ }
208214
209215 // destroy the pool ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
210216
211217 @ Override
212218 public void stop () {
213219 if ( state != null ) {
214220 state .stop ();
221+ validateConnectionsReturned ();
215222 }
216223 }
217224
@@ -234,6 +241,10 @@ public Properties getConnectionProperties() {
234241 return connectionCreator .getConnectionProperties ();
235242 }
236243
244+ @ Override
245+ public boolean isValid (Connection connection ) throws SQLException {
246+ return true ;
247+ }
237248
238249 public static class PooledConnections {
239250
@@ -243,6 +254,7 @@ public static class PooledConnections {
243254 private static final CoreMessageLogger log = CoreLogging .messageLogger ( DriverManagerConnectionProviderImpl .class );
244255
245256 private final ConnectionCreator connectionCreator ;
257+ private final ConnectionValidator connectionValidator ;
246258 private final boolean autoCommit ;
247259 private final int minSize ;
248260 private final int maxSize ;
@@ -253,6 +265,9 @@ private PooledConnections(
253265 Builder builder ) {
254266 log .debugf ( "Initializing Connection pool with %s Connections" , builder .initialSize );
255267 connectionCreator = builder .connectionCreator ;
268+ connectionValidator = builder .connectionValidator == null
269+ ? ConnectionValidator .ALWAYS_VALID
270+ : builder .connectionValidator ;
256271 autoCommit = builder .autoCommit ;
257272 maxSize = builder .maxSize ;
258273 minSize = builder .minSize ;
@@ -283,26 +298,79 @@ else if ( size > maxSize ) {
283298 }
284299
285300 public void add (Connection conn ) throws SQLException {
286- conn .setAutoCommit ( true );
287- conn .clearWarnings ();
288- availableConnections .offer ( conn );
301+ final Connection connection = releaseConnection ( conn );
302+ if ( connection != null ) {
303+ availableConnections .offer ( connection );
304+ }
305+ }
306+
307+ protected Connection releaseConnection (Connection conn ) {
308+ Exception t = null ;
309+ try {
310+ conn .setAutoCommit ( true );
311+ conn .clearWarnings ();
312+ if ( connectionValidator .isValid ( conn ) ) {
313+ return conn ;
314+ }
315+ }
316+ catch (SQLException ex ) {
317+ t = ex ;
318+ }
319+ closeConnection ( conn , t );
320+ log .debug ( "Connection release failed. Closing pooled connection" , t );
321+ return null ;
289322 }
290323
291324 public Connection poll () throws SQLException {
292- Connection conn = availableConnections .poll ();
293- if ( conn == null ) {
294- synchronized (allConnections ) {
295- if (allConnections .size () < maxSize ) {
296- addConnections ( 1 );
297- return poll ();
325+ Connection conn ;
326+ do {
327+ conn = availableConnections .poll ();
328+ if ( conn == null ) {
329+ synchronized (allConnections ) {
330+ if ( allConnections .size () < maxSize ) {
331+ addConnections ( 1 );
332+ return poll ();
333+ }
298334 }
335+ throw new HibernateException (
336+ "The internal connection pool has reached its maximum size and no connection is currently available!" );
299337 }
300- throw new HibernateException ( "The internal connection pool has reached its maximum size and no connection is currently available!" );
301- }
302- conn .setAutoCommit ( autoCommit );
338+ conn = prepareConnection ( conn );
339+ } while ( conn == null );
303340 return conn ;
304341 }
305342
343+ protected Connection prepareConnection (Connection conn ) {
344+ Exception t = null ;
345+ try {
346+ conn .setAutoCommit ( autoCommit );
347+ if ( connectionValidator .isValid ( conn ) ) {
348+ return conn ;
349+ }
350+ }
351+ catch (SQLException ex ) {
352+ t = ex ;
353+ }
354+ closeConnection ( conn , t );
355+ log .debug ( "Connection preparation failed. Closing pooled connection" , t );
356+ return null ;
357+ }
358+
359+ protected void closeConnection (Connection conn , Throwable t ) {
360+ try {
361+ conn .close ();
362+ }
363+ catch (SQLException ex ) {
364+ log .unableToCloseConnection ( ex );
365+ if ( t != null ) {
366+ t .addSuppressed ( ex );
367+ }
368+ }
369+ finally {
370+ allConnections .remove ( conn );
371+ }
372+ }
373+
306374 public void close () throws SQLException {
307375 try {
308376 int allocationCount = allConnections .size () - availableConnections .size ();
@@ -350,6 +418,7 @@ public String getUrl() {
350418
351419 public static class Builder {
352420 private final ConnectionCreator connectionCreator ;
421+ private ConnectionValidator connectionValidator ;
353422 private boolean autoCommit ;
354423 private int initialSize = 1 ;
355424 private int minSize = 1 ;
@@ -375,6 +444,11 @@ public Builder maxSize(int maxSize) {
375444 return this ;
376445 }
377446
447+ public Builder validator (ConnectionValidator connectionValidator ) {
448+ this .connectionValidator = connectionValidator ;
449+ return this ;
450+ }
451+
378452 public PooledConnections build () {
379453 return new PooledConnections ( this );
380454 }
0 commit comments