diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/CannotGetJdbcConnectionException.java b/spring-jdbc/src/main/java/org/springframework/jdbc/CannotGetJdbcConnectionException.java index d5d42d2b34..74e77ae781 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/CannotGetJdbcConnectionException.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/CannotGetJdbcConnectionException.java @@ -25,10 +25,20 @@ import org.springframework.lang.Nullable; * Fatal exception thrown when we can't connect to an RDBMS using JDBC. * * @author Rod Johnson + * @author Juergen Hoeller */ @SuppressWarnings("serial") public class CannotGetJdbcConnectionException extends DataAccessResourceFailureException { + /** + * Constructor for CannotGetJdbcConnectionException. + * @param msg the detail message + * @since 5.0 + */ + public CannotGetJdbcConnectionException(String msg) { + super(msg); + } + /** * Constructor for CannotGetJdbcConnectionException. * @param msg the detail message diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java index 1f1ffbfb0c..a4778b5d9b 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java @@ -78,7 +78,10 @@ public abstract class DataSourceUtils { return doGetConnection(dataSource); } catch (SQLException ex) { - throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex); + throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex); + } + catch (IllegalStateException ex) { + throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection: " + ex.getMessage()); } } @@ -102,14 +105,14 @@ public abstract class DataSourceUtils { conHolder.requested(); if (!conHolder.hasConnection()) { logger.debug("Fetching resumed JDBC Connection from DataSource"); - conHolder.setConnection(dataSource.getConnection()); + conHolder.setConnection(fetchConnection(dataSource)); } return conHolder.getConnection(); } // Else we either got no holder or an empty thread-bound holder here. logger.debug("Fetching JDBC Connection from DataSource"); - Connection con = dataSource.getConnection(); + Connection con = fetchConnection(dataSource); if (TransactionSynchronizationManager.isSynchronizationActive()) { logger.debug("Registering transaction synchronization for JDBC Connection"); @@ -134,6 +137,24 @@ public abstract class DataSourceUtils { return con; } + /** + * Actually fetch a {@link Connection} from the given {@link DataSource}, + * defensively turning an unexpected {@code null} return value from + * {@link DataSource#getConnection()} into an {@link IllegalStateException}. + * @param dataSource the DataSource to obtain Connections from + * @return a JDBC Connection from the given DataSource (never {@code null}) + * @throws SQLException if thrown by JDBC methods + * @throws IllegalStateException if the DataSource returned a null value + * @see DataSource#getConnection() + */ + private static Connection fetchConnection(DataSource dataSource) throws SQLException { + Connection con = dataSource.getConnection(); + if (con == null) { + throw new IllegalStateException("DataSource returned null from getConnection(): " + dataSource); + } + return con; + } + /** * Prepare the given Connection with the given transaction semantics. * @param con the Connection to prepare diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/AbstractEmbeddedDatabaseConfigurer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/AbstractEmbeddedDatabaseConfigurer.java index 6fc983f19c..a78b819350 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/AbstractEmbeddedDatabaseConfigurer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/AbstractEmbeddedDatabaseConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,7 +40,9 @@ abstract class AbstractEmbeddedDatabaseConfigurer implements EmbeddedDatabaseCon Connection con = null; try { con = dataSource.getConnection(); - con.createStatement().execute("SHUTDOWN"); + if (con != null) { + con.createStatement().execute("SHUTDOWN"); + } } catch (SQLException ex) { logger.warn("Could not shut down embedded database", ex); diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java index e5b11349f8..070f41a728 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/DatabaseStartupValidator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -112,6 +112,10 @@ public class DatabaseStartupValidator implements InitializingBean { Statement stmt = null; try { con = this.dataSource.getConnection(); + if (con == null) { + throw new CannotGetJdbcConnectionException("Failed to execute validation query: " + + "DataSource returned null from getConnection(): " + this.dataSource); + } stmt = con.createStatement(); stmt.execute(this.validationQuery); validated = true;