HHH-12252 - Add Agroal to ConnectionProviderInitiator
This commit is contained in:
parent
d29e710c78
commit
1b2424c211
|
@ -9,6 +9,7 @@ hibernate-core:: The main (core) Hibernate module. Defines its ORM features and
|
|||
hibernate-envers:: Hibernate's historical entity versioning feature
|
||||
hibernate-spatial:: Hibernate's Spatial/GIS data-type support
|
||||
hibernate-osgi:: Hibernate support for running in OSGi containers.
|
||||
hibernate-agroal:: Integrates the http://agroal.github.io/[Agroal] connection pooling library into Hibernate
|
||||
hibernate-c3p0:: Integrates the http://www.mchange.com/projects/c3p0/[C3P0] connection pooling library into Hibernate
|
||||
hibernate-hikaricp:: Integrates the http://brettwooldridge.github.io/HikariCP/[HikariCP] connection pooling library into Hibernate
|
||||
hibernate-vibur:: Integrates the http://www.vibur.org/[Vibur DBCP] connection pooling library into Hibernate
|
||||
|
|
|
@ -19,8 +19,9 @@ Hibernate will internally determine which `ConnectionProvider` to use based on t
|
|||
4. else if any setting prefixed by `hibernate.proxool.` is set -> <<database-connectionprovider-proxool>>
|
||||
5. else if any setting prefixed by `hibernate.hikari.` is set -> <<database-connectionprovider-hikari>>
|
||||
6. else if any setting prefixed by `hibernate.vibur.` is set -> <<database-connectionprovider-vibur>>
|
||||
7. else if `hibernate.connection.url` is set -> <<database-connectionprovider-drivermanager>>
|
||||
8. else -> <<database-connectionprovider-provided>>
|
||||
7. else if any setting prefixed by `hibernate.agroal.` is set -> <<database-connectionprovider-agroal>>
|
||||
8. else if `hibernate.connection.url` is set -> <<database-connectionprovider-drivermanager>>
|
||||
9. else -> <<database-connectionprovider-provided>>
|
||||
|
||||
[[database-connectionprovider-datasource]]
|
||||
=== Using DataSources
|
||||
|
@ -137,6 +138,26 @@ Additionally, this `ConnectionProvider` will pick up the following Hibernate-spe
|
|||
`hibernate.connection.isolation`:: Mapped to Vibur's `defaultTransactionIsolationValue` setting. See <<ConnectionProvider support for transaction isolation setting>>.
|
||||
`hibernate.connection.autocommit`:: Mapped to Vibur's `defaultAutoCommit` setting
|
||||
|
||||
[[database-connectionprovider-agroal]]
|
||||
=== Using Agroal
|
||||
|
||||
[IMPORTANT]
|
||||
====
|
||||
To use this integration, the application must include the hibernate-agroal module jar (as well as its dependencies) on the classpath.
|
||||
====
|
||||
|
||||
Hibernate also provides support for applications to use http://agroal.github.io/[Agroal] connection pool.
|
||||
|
||||
Set all of your Agroal settings in Hibernate prefixed by `hibernate.agroal.` and this `ConnectionProvider` will pick them up and pass them along to Agroal connection pool.
|
||||
Additionally, this `ConnectionProvider` will pick up the following Hibernate-specific properties and map them to the corresponding Agroal ones (any `hibernate.agroal.` prefixed ones have precedence):
|
||||
|
||||
`hibernate.connection.driver_class`:: Mapped to Agroal's `driverClassName` setting
|
||||
`hibernate.connection.url`:: Mapped to Agroal's `jdbcUrl` setting
|
||||
`hibernate.connection.username`:: Mapped to Agroal's `principal` setting
|
||||
`hibernate.connection.password`:: Mapped to Agroal's `credential` setting
|
||||
`hibernate.connection.isolation`:: Mapped to Agroal's `jdbcTransactionIsolation` setting. See <<ConnectionProvider support for transaction isolation setting>>.
|
||||
`hibernate.connection.autocommit`:: Mapped to Agroal's `autoCommit` setting
|
||||
|
||||
[[database-connectionprovider-drivermanager]]
|
||||
=== Using Hibernate's built-in (and unsupported) pooling
|
||||
|
||||
|
|
|
@ -131,6 +131,8 @@ ext {
|
|||
proxool: "proxool:proxool:0.8.3",
|
||||
hikaricp: "com.zaxxer:HikariCP:2.5.1",
|
||||
vibur: "org.vibur:vibur-dbcp:21.2",
|
||||
agroal_api: "io.agroal:agroal-api:0.4-SNAPSHOT",
|
||||
agroal_pool: "io.agroal:agroal-pool:0.4-SNAPSHOT",
|
||||
|
||||
cdi: "javax.enterprise:cdi-api:${cdiVersion}",
|
||||
weld: "org.jboss.weld.se:weld-se-shaded:${weldVersion}",
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
apply from: rootProject.file( 'gradle/published-java-module.gradle' )
|
||||
|
||||
description = 'Integration for Agroal as a ConnectionProvider for Hibernate ORM'
|
||||
|
||||
dependencies {
|
||||
compile project( ':hibernate-core' )
|
||||
compile( libraries.agroal_api )
|
||||
runtime( libraries.agroal_pool )
|
||||
testCompile project( ':hibernate-testing' )
|
||||
testCompile(libraries.mockito)
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
package org.hibernate.agroal.internal;
|
||||
|
||||
import io.agroal.api.AgroalDataSource;
|
||||
import io.agroal.api.configuration.AgroalConnectionFactoryConfiguration;
|
||||
import io.agroal.api.configuration.supplier.AgroalConnectionFactoryConfigurationSupplier;
|
||||
import io.agroal.api.configuration.supplier.AgroalPropertiesReader;
|
||||
import io.agroal.api.security.NamePrincipal;
|
||||
import io.agroal.api.security.SimplePassword;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator;
|
||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.service.UnknownUnwrapTypeException;
|
||||
import org.hibernate.service.spi.Configurable;
|
||||
import org.hibernate.service.spi.Stoppable;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* ConnectionProvider based on Agroal connection pool
|
||||
* To use this ConnectionProvider set: <pre> hibernate.connection.provider_class AgroalConnectionProvider </pre>
|
||||
* ( @see AvailableSettings#CONNECTION_PROVIDER )
|
||||
*
|
||||
* Usual hibernate properties are supported:
|
||||
* <pre>
|
||||
* hibernate.connection.driver_class
|
||||
* hibernate.connection.url
|
||||
* hibernate.connection.username
|
||||
* hibernate.connection.password
|
||||
* hibernate.connection.autocommit
|
||||
* hibernate.connection.isolation
|
||||
* </pre>
|
||||
*
|
||||
* Other configuration options are available, using the <pre>hibernate.agroal</pre> prefix ( @see AgroalPropertiesReader )
|
||||
*
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
public class AgroalConnectionProvider implements ConnectionProvider, Configurable, Stoppable {
|
||||
|
||||
public static final String CONFIG_PREFIX = "hibernate.agroal.";
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger( AgroalConnectionProvider.class );
|
||||
private AgroalDataSource agroalDataSource = null;
|
||||
|
||||
// --- Configurable
|
||||
|
||||
private static void resolveIsolationSetting(Map<String, String> properties, AgroalConnectionFactoryConfigurationSupplier cf) {
|
||||
Integer isolation = ConnectionProviderInitiator.extractIsolation( properties );
|
||||
if ( isolation != null ) {
|
||||
// Agroal resolves transaction isolation from the 'nice' name
|
||||
String isolationString = ConnectionProviderInitiator.toIsolationNiceName( isolation );
|
||||
cf.jdbcTransactionIsolation( AgroalConnectionFactoryConfiguration.TransactionIsolation.valueOf( isolationString ) );
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> void copyProperty(Map<String, String> properties, String key, Consumer<T> consumer, Function<String, T> converter) {
|
||||
String value = properties.get( key );
|
||||
if ( value != null ) {
|
||||
consumer.accept( converter.apply( value ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public void configure(Map props) throws HibernateException {
|
||||
LOGGER.debug( "Configuring Agroal" );
|
||||
try {
|
||||
AgroalPropertiesReader agroalProperties = new AgroalPropertiesReader( CONFIG_PREFIX ).readProperties( props );
|
||||
agroalProperties.modify().connectionPoolConfiguration( cp -> cp.connectionFactoryConfiguration( cf -> {
|
||||
copyProperty( props, AvailableSettings.DRIVER, cf::driverClassName, Function.identity() );
|
||||
copyProperty( props, AvailableSettings.URL, cf::jdbcUrl, Function.identity() );
|
||||
copyProperty( props, AvailableSettings.USER, cf::principal, NamePrincipal::new );
|
||||
copyProperty( props, AvailableSettings.PASS, cf::credential, SimplePassword::new );
|
||||
copyProperty( props, AvailableSettings.AUTOCOMMIT, cf::autoCommit, Boolean::valueOf );
|
||||
resolveIsolationSetting( props, cf );
|
||||
return cf;
|
||||
} ) );
|
||||
|
||||
agroalDataSource = AgroalDataSource.from( agroalProperties );
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new HibernateException( e );
|
||||
}
|
||||
LOGGER.debug( "Agroal Configured" );
|
||||
}
|
||||
|
||||
// --- ConnectionProvider
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
return agroalDataSource == null ? null : agroalDataSource.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnection(Connection conn) throws SQLException {
|
||||
conn.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsAggressiveRelease() {
|
||||
// Agroal supports integration with Narayana as the JTA provider, that would enable aggressive release
|
||||
// That logic is similar with what Hibernate does (however with better performance since it's integrated in the pool)
|
||||
// and therefore that integration is not leveraged right now.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings( "rawtypes" )
|
||||
public boolean isUnwrappableAs(Class unwrapType) {
|
||||
return ConnectionProvider.class.equals( unwrapType ) || AgroalConnectionProvider.class.isAssignableFrom( unwrapType ) || DataSource.class.isAssignableFrom( unwrapType );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public <T> T unwrap(Class<T> unwrapType) {
|
||||
if ( ConnectionProvider.class.equals( unwrapType ) || AgroalConnectionProvider.class.isAssignableFrom( unwrapType ) ) {
|
||||
return (T) this;
|
||||
}
|
||||
if ( DataSource.class.isAssignableFrom( unwrapType ) ) {
|
||||
return (T) agroalDataSource;
|
||||
}
|
||||
throw new UnknownUnwrapTypeException( unwrapType );
|
||||
}
|
||||
|
||||
// --- Stoppable
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
agroalDataSource.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.agroal.internal;
|
||||
|
||||
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistration;
|
||||
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
|
||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides the {@link AgroalConnectionProvider} to the
|
||||
* {@link org.hibernate.boot.registry.selector.spi.StrategySelector} service.
|
||||
*
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
public class StrategyRegistrationProviderImpl implements StrategyRegistrationProvider {
|
||||
|
||||
private static final List<StrategyRegistration> REGISTRATIONS = Collections.singletonList(
|
||||
new SimpleStrategyRegistrationImpl<>(
|
||||
ConnectionProvider.class,
|
||||
AgroalConnectionProvider.class,
|
||||
AgroalConnectionProvider.class.getSimpleName(),
|
||||
"agroal",
|
||||
"Agroal",
|
||||
// for consistency's sake
|
||||
"org.hibernate.connection.AgroalConnectionProvider"
|
||||
)
|
||||
);
|
||||
|
||||
@Override
|
||||
public Iterable<StrategyRegistration> getStrategyRegistrations() {
|
||||
return REGISTRATIONS;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of ConnectionProvider using Agroal.
|
||||
*/
|
||||
package org.hibernate.agroal.internal;
|
|
@ -0,0 +1,13 @@
|
|||
#
|
||||
# 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
#
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
#
|
||||
org.hibernate.agroal.internal.StrategyRegistrationProviderImpl
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<blueprint default-activation="eager"
|
||||
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<bean id="strategyRegistrationProvider" class="org.hibernate.agroal.internal.StrategyRegistrationProviderImpl"/>
|
||||
<service ref="strategyRegistrationProvider" interface="org.hibernate.boot.registry.selector.StrategyRegistrationProvider"/>
|
||||
|
||||
</blueprint>
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.agroal;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.ConnectionProviderJdbcConnectionAccess;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.agroal.internal.AgroalConnectionProvider;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
public class AgroalConnectionProviderTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Test
|
||||
public void testAgroalConnectionProvider() throws Exception {
|
||||
JdbcServices jdbcServices = serviceRegistry().getService( JdbcServices.class );
|
||||
ConnectionProviderJdbcConnectionAccess connectionAccess = assertTyping(
|
||||
ConnectionProviderJdbcConnectionAccess.class,
|
||||
jdbcServices.getBootstrapJdbcConnectionAccess()
|
||||
);
|
||||
assertTyping( AgroalConnectionProvider.class, connectionAccess.getConnectionProvider() );
|
||||
|
||||
AgroalConnectionProvider agroalConnectionProvider = (AgroalConnectionProvider) connectionAccess.getConnectionProvider();
|
||||
// For simplicity's sake, using the following in hibernate.properties:
|
||||
// hibernate.agroal.maxSize 2
|
||||
// hibernate.agroal.minSize 2
|
||||
List<Connection> conns = new ArrayList<>();
|
||||
for ( int i = 0; i < 2; i++ ) {
|
||||
Connection conn = agroalConnectionProvider.getConnection();
|
||||
assertNotNull( conn );
|
||||
assertFalse( conn.isClosed() );
|
||||
conns.add( conn );
|
||||
}
|
||||
|
||||
try {
|
||||
agroalConnectionProvider.getConnection();
|
||||
fail( "SQLException expected -- no more connections should have been available in the pool." );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
// expected
|
||||
assertTrue( e.getMessage().contains( "timeout" ) );
|
||||
}
|
||||
|
||||
for ( Connection conn : conns ) {
|
||||
agroalConnectionProvider.closeConnection( conn );
|
||||
assertTrue( conn.isClosed() );
|
||||
}
|
||||
|
||||
releaseSessionFactory();
|
||||
|
||||
try {
|
||||
agroalConnectionProvider.getConnection();
|
||||
fail( "Exception expected -- the pool should have been shutdown." );
|
||||
}
|
||||
catch (Exception e) {
|
||||
// expected
|
||||
assertTrue( e.getMessage().contains( "closed" ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.agroal;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.test.agroal.util.PreparedStatementSpyConnectionProvider;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class AgroalSkipAutoCommitTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration configuration) {
|
||||
configuration.getProperties().put( AvailableSettings.CONNECTION_PROVIDER, connectionProvider );
|
||||
configuration.getProperties().put( AvailableSettings.CONNECTION_PROVIDER_DISABLES_AUTOCOMMIT, Boolean.TRUE );
|
||||
configuration.getProperties().put( AvailableSettings.AUTOCOMMIT, Boolean.FALSE.toString() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseSessionFactory() {
|
||||
super.releaseSessionFactory();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{ City.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
connectionProvider.clear();
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
City city = new City();
|
||||
city.setId( 1L );
|
||||
city.setName( "Cluj-Napoca" );
|
||||
session.persist( city );
|
||||
|
||||
assertTrue( connectionProvider.getAcquiredConnections().isEmpty() );
|
||||
assertTrue( connectionProvider.getReleasedConnections().isEmpty() );
|
||||
} );
|
||||
verifyConnections();
|
||||
|
||||
connectionProvider.clear();
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
City city = session.find( City.class, 1L );
|
||||
assertEquals( "Cluj-Napoca", city.getName() );
|
||||
} );
|
||||
verifyConnections();
|
||||
}
|
||||
|
||||
private void verifyConnections() {
|
||||
assertTrue( connectionProvider.getAcquiredConnections().isEmpty() );
|
||||
|
||||
List<Connection> connections = connectionProvider.getReleasedConnections();
|
||||
assertEquals( 1, connections.size() );
|
||||
Connection connection = connections.get( 0 );
|
||||
try {
|
||||
verify(connection, never()).setAutoCommit( false );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "City" )
|
||||
public static class City {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.agroal;
|
||||
|
||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.agroal.internal.AgroalConnectionProvider;
|
||||
|
||||
import org.hibernate.testing.common.connections.BaseTransactionIsolationConfigTest;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class AgroalTransactionIsolationConfigTest extends BaseTransactionIsolationConfigTest {
|
||||
@Override
|
||||
protected ConnectionProvider getConnectionProviderUnderTest() {
|
||||
return new AgroalConnectionProvider();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.agroal.util;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.agroal.internal.AgroalConnectionProvider;
|
||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.internal.util.MockUtil;
|
||||
|
||||
/**
|
||||
* This {@link ConnectionProvider} extends any other ConnectionProvider that would be used by default taken the current configuration properties, and it
|
||||
* intercept the underlying {@link PreparedStatement} method calls.
|
||||
*
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class PreparedStatementSpyConnectionProvider extends AgroalConnectionProvider {
|
||||
|
||||
private final Map<PreparedStatement, String> preparedStatementMap = new LinkedHashMap<>();
|
||||
|
||||
private final List<Connection> acquiredConnections = new ArrayList<>( );
|
||||
private final List<Connection> releasedConnections = new ArrayList<>( );
|
||||
|
||||
public PreparedStatementSpyConnectionProvider() {
|
||||
}
|
||||
|
||||
protected Connection actualConnection() throws SQLException {
|
||||
return super.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
Connection connection = spy( actualConnection() );
|
||||
acquiredConnections.add( connection );
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnection(Connection conn) throws SQLException {
|
||||
acquiredConnections.remove( conn );
|
||||
releasedConnections.add( conn );
|
||||
super.closeConnection( conn );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
clear();
|
||||
super.stop();
|
||||
}
|
||||
|
||||
private Connection spy(Connection connection) {
|
||||
if ( MockUtil.isMock( connection ) ) {
|
||||
return connection;
|
||||
}
|
||||
Connection connectionSpy = Mockito.spy( connection );
|
||||
try {
|
||||
Mockito.doAnswer( invocation -> {
|
||||
PreparedStatement statement = (PreparedStatement) invocation.callRealMethod();
|
||||
PreparedStatement statementSpy = Mockito.spy( statement );
|
||||
String sql = (String) invocation.getArguments()[0];
|
||||
preparedStatementMap.put( statementSpy, sql );
|
||||
return statementSpy;
|
||||
} ).when( connectionSpy ).prepareStatement( ArgumentMatchers.anyString() );
|
||||
|
||||
Mockito.doAnswer( invocation -> {
|
||||
Statement statement = (Statement) invocation.callRealMethod();
|
||||
Statement statementSpy = Mockito.spy( statement );
|
||||
return statementSpy;
|
||||
} ).when( connectionSpy ).createStatement();
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw new IllegalArgumentException( e );
|
||||
}
|
||||
return connectionSpy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the recorded PreparedStatements and reset the associated Mocks.
|
||||
*/
|
||||
public void clear() {
|
||||
acquiredConnections.clear();
|
||||
releasedConnections.clear();
|
||||
preparedStatementMap.keySet().forEach( Mockito::reset );
|
||||
preparedStatementMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of current acquired Connections.
|
||||
* @return list of current acquired Connections
|
||||
*/
|
||||
public List<Connection> getAcquiredConnections() {
|
||||
return acquiredConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of current released Connections.
|
||||
* @return list of current released Connections
|
||||
*/
|
||||
public List<Connection> getReleasedConnections() {
|
||||
return releasedConnections;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
#
|
||||
hibernate.dialect @db.dialect@
|
||||
hibernate.connection.driver_class @jdbc.driver@
|
||||
hibernate.connection.url @jdbc.url@
|
||||
hibernate.connection.username @jdbc.user@
|
||||
hibernate.connection.password @jdbc.pass@
|
||||
|
||||
hibernate.jdbc.batch_size 10
|
||||
hibernate.connection.provider_class AgroalConnectionProvider
|
||||
|
||||
hibernate.agroal.maxSize 2
|
||||
hibernate.agroal.acquisitionTimeout PT1s
|
||||
hibernate.agroal.reapTimeout PT10s
|
|
@ -0,0 +1,60 @@
|
|||
#
|
||||
# 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
#
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
|
||||
#log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L (hibernateLoadPlanWalkPath->%X{hibernateLoadPlanWalkPath}) - %m%n
|
||||
|
||||
#log4j.appender.stdout-mdc=org.apache.log4j.ConsoleAppender
|
||||
#log4j.appender.stdout-mdc.Target=System.out
|
||||
#log4j.appender.stdout-mdc.layout=org.apache.log4j.PatternLayout
|
||||
#log4j.appender.stdout-mdc.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L (walk path -> %X{hibernateLoadPlanWalkPath}) - %m%n
|
||||
|
||||
log4j.appender.unclosedSessionFactoryFile=org.apache.log4j.FileAppender
|
||||
log4j.appender.unclosedSessionFactoryFile.append=true
|
||||
log4j.appender.unclosedSessionFactoryFile.file=target/tmp/log/UnclosedSessionFactoryWarnings.log
|
||||
log4j.appender.unclosedSessionFactoryFile.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.unclosedSessionFactoryFile.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
|
||||
|
||||
log4j.rootLogger=info, stdout
|
||||
|
||||
#log4j.logger.org.hibernate.loader.plan=trace, stdout-mdc
|
||||
#log4j.additivity.org.hibernate.loader.plan=false
|
||||
#log4j.logger.org.hibernate.persister.walking=trace, stdout-mdc
|
||||
#log4j.additivity.org.hibernate.persister.walking=false
|
||||
|
||||
log4j.logger.org.hibernate.tool.hbm2ddl=trace
|
||||
log4j.logger.org.hibernate.testing.cache=debug
|
||||
|
||||
# SQL Logging - HHH-6833
|
||||
log4j.logger.org.hibernate.SQL=debug
|
||||
|
||||
log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=trace
|
||||
log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=trace
|
||||
|
||||
log4j.logger.org.hibernate.hql.internal.ast=debug
|
||||
|
||||
log4j.logger.org.hibernate.sql.ordering.antlr=debug
|
||||
|
||||
log4j.logger.org.hibernate.loader.plan2.build.internal.LoadPlanImpl=debug
|
||||
log4j.logger.org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter=debug
|
||||
log4j.logger.org.hibernate.loader.plan2.exec.spi.EntityLoadQueryDetails=debug
|
||||
|
||||
log4j.logger.org.hibernate.engine.internal.StatisticalLoggingSessionEventListener=info
|
||||
|
||||
log4j.logger.org.hibernate.boot.model.source.internal.hbm.ModelBinder=debug
|
||||
log4j.logger.org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry=debug
|
||||
|
||||
|
||||
### When entity copy merge functionality is enabled using:
|
||||
### hibernate.event.merge.entity_copy_observer=log, the following will
|
||||
### provide information about merged entity copies.
|
||||
### log4j.logger.org.hibernate.event.internal.EntityCopyAllowedLoggedObserver=debug
|
||||
|
||||
log4j.logger.org.hibernate.testing.junit4.TestClassMetadata=info, unclosedSessionFactoryFile
|
||||
log4j.logger.org.hibernate.boot.model.process.internal.ScanningCoordinator=debug
|
|
@ -0,0 +1 @@
|
|||
mock-maker-inline
|
|
@ -65,6 +65,11 @@ public class ConnectionProviderInitiator implements StandardServiceInitiator<Con
|
|||
*/
|
||||
public static final String VIBUR_STRATEGY = "vibur";
|
||||
|
||||
/**
|
||||
* The strategy for agroal connection pooling
|
||||
*/
|
||||
public static final String AGROAL_STRATEGY = "agroal";
|
||||
|
||||
/**
|
||||
* No idea. Is this even still used?
|
||||
*/
|
||||
|
@ -165,6 +170,12 @@ public class ConnectionProviderInitiator implements StandardServiceInitiator<Con
|
|||
}
|
||||
}
|
||||
|
||||
if ( connectionProvider == null ) {
|
||||
if ( agroalConfigDefined( configurationValues ) ) {
|
||||
connectionProvider = instantiateAgroalProvider( strategySelector );
|
||||
}
|
||||
}
|
||||
|
||||
if ( connectionProvider == null ) {
|
||||
if ( configurationValues.get( AvailableSettings.URL ) != null ) {
|
||||
connectionProvider = new DriverManagerConnectionProviderImpl();
|
||||
|
@ -288,6 +299,20 @@ public class ConnectionProviderInitiator implements StandardServiceInitiator<Con
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
private boolean agroalConfigDefined(Map configValues) {
|
||||
for ( Object key : configValues.keySet() ) {
|
||||
if ( !String.class.isInstance( key ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ( (String) key ).startsWith( "hibernate.agroal." ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private ConnectionProvider instantiateViburProvider(StrategySelector strategySelector) {
|
||||
try {
|
||||
return strategySelector.selectStrategyImplementor( ConnectionProvider.class, VIBUR_STRATEGY ).newInstance();
|
||||
|
@ -298,6 +323,16 @@ public class ConnectionProviderInitiator implements StandardServiceInitiator<Con
|
|||
}
|
||||
}
|
||||
|
||||
private ConnectionProvider instantiateAgroalProvider(StrategySelector strategySelector) {
|
||||
try {
|
||||
return strategySelector.selectStrategyImplementor( ConnectionProvider.class, AGROAL_STRATEGY ).newInstance();
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
LOG.agroalProviderClassNotFound();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the connection properties capable of being passed to the {@link java.sql.DriverManager#getConnection}
|
||||
* forms taking {@link Properties} argument. We seek out all keys in the passed map which start with
|
||||
|
|
|
@ -1795,4 +1795,10 @@ public interface CoreMessageLogger extends BasicLogger {
|
|||
Object id
|
||||
);
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(value = "Agroal properties were encountered, but the Agroal ConnectionProvider was not found on the classpath; these properties are going to be ignored.",
|
||||
id = 486)
|
||||
void agroalProviderClassNotFound();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ include 'hibernate-c3p0'
|
|||
include 'hibernate-proxool'
|
||||
include 'hibernate-hikaricp'
|
||||
include 'hibernate-vibur'
|
||||
include 'hibernate-agroal'
|
||||
|
||||
include 'hibernate-jcache'
|
||||
include 'hibernate-ehcache'
|
||||
|
|
Loading…
Reference in New Issue