diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java index 90e40ef05d..7d505c1bfe 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java @@ -130,7 +130,12 @@ public class SchemaUpdate { ); } - schemaMigrator.doMigration( metadata, databaseInformation, true, toolTargets ); + try { + schemaMigrator.doMigration( metadata, databaseInformation, true, toolTargets ); + } + finally { + databaseInformation.cleanup(); + } } private List buildToolTargets(Target target) { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java index e995fbce96..9973423e4a 100755 --- a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java @@ -86,9 +86,13 @@ public class SchemaValidator { "Error creating DatabaseInformation for schema validation" ); } - - serviceRegistry.getService( SchemaManagementTool.class ).getSchemaValidator( cfgService.getSettings() ) - .doValidation( metadata, databaseInformation ); + try { + serviceRegistry.getService( SchemaManagementTool.class ).getSchemaValidator( cfgService.getSettings() ) + .doValidation( metadata, databaseInformation ); + } + finally { + databaseInformation.cleanup(); + } } public static void main(String[] args) { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java index 446157a6c6..1dab55e267 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java @@ -152,4 +152,9 @@ public class DatabaseInformationImpl implements DatabaseInformation, ExtractionC return sequenceInformationMap.get( sequenceName ); } + + @Override + public void cleanup() { + extractionContext.cleanup(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java index 6fcb66fd7a..9da18060d2 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java @@ -96,6 +96,7 @@ public class ExtractionContextImpl implements ExtractionContext { return registeredTableAccess; } + @Override public void cleanup() { if ( jdbcDatabaseMetaData != null ) { jdbcDatabaseMetaData = null; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/DatabaseInformation.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/DatabaseInformation.java index 338538d679..7a9e5154d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/DatabaseInformation.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/DatabaseInformation.java @@ -101,4 +101,6 @@ public interface DatabaseInformation { * @return {@code true} indicates a catalog with the given name already exists */ boolean catalogExists(Identifier catalog); + + void cleanup(); } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java index 8a9d3a9a90..afdf6f97c2 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java @@ -40,4 +40,6 @@ public interface ExtractionContext { } DatabaseObjectAccess getDatabaseObjectAccess(); + + void cleanup(); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/ConnectionsReleaseTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/ConnectionsReleaseTest.java new file mode 100644 index 0000000000..72dc2e33d3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/ConnectionsReleaseTest.java @@ -0,0 +1,117 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.schemaupdate; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.tool.hbm2ddl.SchemaUpdate; +import org.hibernate.tool.hbm2ddl.SchemaValidator; +import org.hibernate.tool.hbm2ddl.Target; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +/** + * @author Andrea Boriero + */ +@TestForIssue(jiraKey = "HHH-10443") +public class ConnectionsReleaseTest extends BaseUnitTestCase { + + public static Properties getConnectionProviderProperties() { + Properties props = new Properties(); + props.put( Environment.DRIVER, "org.h2.Driver" ); + props.put( Environment.URL, String.format( "jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1", "db1" ) ); + props.put( Environment.USER, "sa" ); + props.put( Environment.PASS, "" ); + return props; + } + + private StandardServiceRegistry ssr; + private MetadataImplementor metadata; + private ConnectionProviderDecorator connectionProvider; + + @Before + public void setUp() { + connectionProvider = new ConnectionProviderDecorator(); + connectionProvider.configure( getConnectionProviderProperties() ); + + ssr = new StandardServiceRegistryBuilder() + .addService( ConnectionProvider.class, connectionProvider ) + .build(); + metadata = (MetadataImplementor) new MetadataSources( ssr ) + .addAnnotatedClass( Thing.class ) + .buildMetadata(); + metadata.validate(); + } + + @After + public void tearDown() { + StandardServiceRegistryBuilder.destroy( ssr ); + } + + @Test + public void testSchemaUpdateReleasesAllConnections() throws SQLException { + + new SchemaUpdate( ssr, metadata ).execute( Target.EXPORT ); + + assertThat( connectionProvider.getOpenConnection(), is( 0 ) ); + } + + @Test + public void testSchemaValidatorReleasesAllConnections() throws SQLException { + + new SchemaValidator( ssr, metadata ).validate(); + + assertThat( connectionProvider.getOpenConnection(), is( 0 ) ); + } + + @Entity(name = "Thing") + @Table(name = "Thing") + public static class Thing { + @Id + public Integer id; + } + + public static class ConnectionProviderDecorator extends DriverManagerConnectionProviderImpl { + private int openConnection; + + @Override + public Connection getConnection() throws SQLException { + openConnection++; + return super.getConnection(); + } + + @Override + public void closeConnection(Connection conn) throws SQLException { + super.closeConnection( conn ); + openConnection--; + } + + public int getOpenConnection() { + return this.openConnection; + } + } +}