Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -355,9 +355,11 @@ You can set the size of Hibernate's built-in connection pool using this property
|===
| Configuration property name | Purpose

| `hibernate.connection.pool_size` | The size of the built-in connection pool
| `hibernate.connection.pool_size` | The size of the connection pool
|===

This configuration property is also respected when you use Agroal, HikariCP, or c3p0 for connection pooling.

[CAUTION]
// .The default connection pool is not meant for production use
====
Expand Down
1 change: 1 addition & 0 deletions documentation/src/main/asciidoc/introduction/Tuning.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ The following settings are common to all connection pools supported by Hibernate
.Common settings for connection pools
[%breakable,cols="37,~"]
|===
| link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#POOL_SIZE[`hibernate.connection.pool_size`] | The size of the connection pool
| link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#AUTOCOMMIT[`hibernate.connection.autocommit`] | The default autocommit mode
| link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#ISOLATION[`hibernate.connection.isolation`] | The default transaction isolation level
|===
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,24 @@
*/
package org.hibernate.agroal.internal;

import java.io.Serial;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.DatabaseMetaData;
import javax.sql.DataSource;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;

import io.agroal.api.configuration.AgroalConnectionFactoryConfiguration.TransactionIsolation;
import org.hibernate.HibernateException;
import org.hibernate.cfg.AgroalSettings;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.JdbcSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator;
import org.hibernate.engine.jdbc.connections.internal.DatabaseConnectionInfoImpl;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProviderConfigurationException;
import org.hibernate.engine.jdbc.connections.spi.DatabaseConnectionInfo;
import org.hibernate.internal.log.ConnectionInfoLogger;
import org.hibernate.service.UnknownUnwrapTypeException;
Expand All @@ -33,14 +36,19 @@
import io.agroal.api.security.NamePrincipal;
import io.agroal.api.security.SimplePassword;

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import static org.hibernate.cfg.AgroalSettings.AGROAL_CONFIG_PREFIX;
import static org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.allowJdbcMetadataAccess;

/**
* ConnectionProvider based on Agroal connection pool
* To use this ConnectionProvider set: <pre> hibernate.connection.provider_class AgroalConnectionProvider </pre>
*
* Usual hibernate properties are supported:
* {@link ConnectionProvider} based on Agroal connection pool.
* <p>
* To force the use of this {@code ConnectionProvider} set
* {@value org.hibernate.cfg.JdbcSettings#CONNECTION_PROVIDER}
* to {@code agroal}.
* <p>
* Usual hibernate connection properties are supported:
* <pre>
* hibernate.connection.driver_class
* hibernate.connection.url
Expand All @@ -49,8 +57,8 @@
* hibernate.connection.autocommit
* hibernate.connection.isolation
* </pre>
*
* Other configuration options are available, using the {@code hibernate.agroal} prefix
* <p>
* Other configuration options are available, using the {@code hibernate.agroal} prefix.
*
* @see AgroalSettings
* @see AgroalPropertiesReader
Expand All @@ -61,61 +69,78 @@
public class AgroalConnectionProvider implements ConnectionProvider, Configurable, Stoppable {

public static final String CONFIG_PREFIX = AGROAL_CONFIG_PREFIX + ".";

@Serial
private static final long serialVersionUID = 1L;
private AgroalDataSource agroalDataSource = null;
private boolean isMetadataAccessAllowed = true;

// --- Configurable

private static String extractIsolationAsString(Map<String, Object> properties) {
Integer isolation = ConnectionProviderInitiator.extractIsolation( properties );
if ( isolation != null ) {
// Agroal resolves transaction isolation from the 'nice' name
return ConnectionProviderInitiator.toIsolationNiceName( isolation );
}
return null;
final Integer isolation = ConnectionProviderInitiator.extractIsolation( properties );
return isolation != null ?
// Agroal resolves transaction isolation from the 'nice' name
ConnectionProviderInitiator.toIsolationNiceName( isolation )
: null;
}

private static void resolveIsolationSetting(Map<String, Object> properties, AgroalConnectionFactoryConfigurationSupplier cf) {
String isolationString = extractIsolationAsString( properties );
final String isolationString = extractIsolationAsString( properties );
if ( isolationString != null ) {
cf.jdbcTransactionIsolation( AgroalConnectionFactoryConfiguration.TransactionIsolation.valueOf( isolationString ) );
cf.jdbcTransactionIsolation( TransactionIsolation.valueOf( isolationString ) );
}
}

private static <T> void copyProperty(Map<String, Object> properties, String key, Consumer<T> consumer, Function<String, T> converter) {
Object value = properties.get( key );
if ( value instanceof String ) {
consumer.accept( converter.apply( (String) value ) );
final Object value = properties.get( key );
if ( value != null ) {
consumer.accept( converter.apply( value.toString() ) );
}
}

@Override
public void configure(Map<String, Object> props) throws HibernateException {
isMetadataAccessAllowed = allowJdbcMetadataAccess( props );
public void configure(Map<String, Object> properties) throws HibernateException {
isMetadataAccessAllowed = allowJdbcMetadataAccess( properties );

ConnectionInfoLogger.INSTANCE.configureConnectionPool( "Agroal" );
try {
AgroalPropertiesReader agroalProperties = new AgroalPropertiesReader( CONFIG_PREFIX )
.readProperties( (Map) props ); //TODO: this is a garbage cast
agroalProperties.modify().connectionPoolConfiguration( cp -> cp.connectionFactoryConfiguration( cf -> {
copyProperty( props, AvailableSettings.DRIVER, cf::connectionProviderClassName, 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 );
final Map<String, String> config = toStringValuedProperties( properties );
if ( !properties.containsKey( AgroalSettings.AGROAL_MAX_SIZE ) ) {
final String maxSize =
properties.containsKey( JdbcSettings.POOL_SIZE )
? properties.get( JdbcSettings.POOL_SIZE ).toString()
: String.valueOf( 10 );
config.put( AgroalSettings.AGROAL_MAX_SIZE, maxSize );
}
final AgroalPropertiesReader agroalProperties =
new AgroalPropertiesReader( CONFIG_PREFIX )
.readProperties( config );
agroalProperties.modify()
.connectionPoolConfiguration( cp -> cp.connectionFactoryConfiguration( cf -> {
copyProperty( properties, JdbcSettings.DRIVER, cf::connectionProviderClassName, identity() );
copyProperty( properties, JdbcSettings.URL, cf::jdbcUrl, identity() );
copyProperty( properties, JdbcSettings.USER, cf::principal, NamePrincipal::new );
copyProperty( properties, JdbcSettings.PASS, cf::credential, SimplePassword::new );
copyProperty( properties, JdbcSettings.AUTOCOMMIT, cf::autoCommit, Boolean::valueOf );
resolveIsolationSetting( properties, cf );
return cf;
} ) );

agroalDataSource = AgroalDataSource.from( agroalProperties );
}
catch ( Exception e ) {
ConnectionInfoLogger.INSTANCE.unableToInstantiateConnectionPool( e );
throw new HibernateException( e );
throw new ConnectionProviderConfigurationException(
"Could not configure Agroal: " + e.getMessage(), e );
}
}

private static Map<String,String> toStringValuedProperties(Map<String,Object> properties) {
return properties.entrySet().stream()
.collect( toMap( Map.Entry::getKey, e -> e.getValue().toString() ) );
}

// --- ConnectionProvider

@Override
Expand All @@ -138,30 +163,31 @@ public boolean supportsAggressiveRelease() {

@Override
public DatabaseConnectionInfo getDatabaseConnectionInfo(Dialect dialect) {
final AgroalConnectionPoolConfiguration acpc = agroalDataSource.getConfiguration().connectionPoolConfiguration();
final AgroalConnectionPoolConfiguration acpc =
agroalDataSource.getConfiguration().connectionPoolConfiguration();
final AgroalConnectionFactoryConfiguration acfc = acpc.connectionFactoryConfiguration();


return new DatabaseConnectionInfoImpl(
acfc.jdbcUrl(),
// Attempt to resolve the driver name from the dialect, in case it wasn't explicitly set and access to
// the database metadata is allowed
acfc.connectionProviderClass() != null ? acfc.connectionProviderClass().toString() : extractDriverNameFromMetadata(),
// Attempt to resolve the driver name from the dialect,
// in case it wasn't explicitly set and access to the
// database metadata is allowed
acfc.connectionProviderClass() != null
? acfc.connectionProviderClass().toString()
: extractDriverNameFromMetadata(),
dialect.getVersion(),
Boolean.toString( acfc.autoCommit() ),
acfc.jdbcTransactionIsolation() != null
? ConnectionProviderInitiator.toIsolationNiceName( acfc.jdbcTransactionIsolation().level() )
: null,
acpc.minSize(),
acpc.minSize()
acpc.maxSize()
);
}

private String extractDriverNameFromMetadata() {
if (isMetadataAccessAllowed) {
try ( Connection conn = getConnection() ) {
DatabaseMetaData dbmd = conn.getMetaData();
return dbmd.getDriverName();
return conn.getMetaData().getDriverName();
}
catch (SQLException e) {
// Do nothing
Expand Down Expand Up @@ -195,8 +221,11 @@ public <T> T unwrap(Class<T> unwrapType) {
@Override
public void stop() {
if ( agroalDataSource != null ) {
ConnectionInfoLogger.INSTANCE.cleaningUpConnectionPool( agroalDataSource.getConfiguration().connectionPoolConfiguration().
connectionFactoryConfiguration().jdbcUrl() );
ConnectionInfoLogger.INSTANCE.cleaningUpConnectionPool(
agroalDataSource.getConfiguration()
.connectionPoolConfiguration()
.connectionFactoryConfiguration()
.jdbcUrl() );
agroalDataSource.close();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
*/

/**
* Implementation of ConnectionProvider using Agroal.
* Implementation of {@code ConnectionProvider} using Agroal.
*/
package org.hibernate.agroal.internal;
Loading
Loading