X

Learn Tips and Best Practices from the Oracle JDBC Development

  • May 21, 2015

Use UCP with Hibernate





Hibernate ORM is an object/relational mapping framework for Java. Out-of-box, Hibernate supports two open source connection pools C3P0 and Proxool.

Universal Connection Pool (UCP) is Oracle’s feature-rich Java connection pool, replacing the Implicit Connection Cache (ICC), which has been de-supported in Oracle Database 12c. Besides standard connection pooling features, UCP has also been designed for scalability and high-availability during planned and unplanned database downtimes, with seamless support for Oracle Real Application Clusters (RAC), Active Data Guard (ADG) and Global Data Services (GDS).

This article illustrates a couple of options for using Oracle Universal Connection Pool (UCP) with Hibernate. The code samples are for demonstration purpose only.


Using UCP data source via JNDI lookup

If the target application can use JNDI to lookup a data source (for example, when using Tomcat), then users can specify a UCP data source for Hibernate to use, by using the Hibernate property "hibernate.connection.datasource". This can be done either declaratively in a Hibernate configuration file (XML or properties file), or programmatically on org.hibernate.cfg.Configuration.

For example, after binding a UCP PoolDataSource in JNDI, users can specify in hibernate.cfg.xml:

<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.datasource">
java:comp/env/UCP_PoolDataSource_JNDI_NAME
</property>

All the UCP connection pool and data source configurations should be done on the PoolDataSource, before binding it in JNDI.


Using UCP data source with Spring framework

If the target application can use Spring along with Hibernate, then UCP data sources can be configured in Spring configuration XML files.

For example:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Initialization for data source -->
<bean id="dataSource" class="oracle.ucp.jdbc.PoolDataSourceImpl">
<property name="connectionFactoryClassName" value="oracle.jdbc.pool.OracleDataSource"/>
<property name="URL" value="jdbc:oracle:thin:@//host:port/service_name"/>
<property name="user" value="scott"/>
<property name="password" value="tiger"/>
<property name="maxPoolSize" value="10"/>
<property name="initialPoolSize" value="5"/>
</bean>
<!-- Definition for EmpJDBCTemplate bean -->
<bean id="EmpJDBCTemplate" class="test.EmpJDBCTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>


Implementing UCP as a Hibernate ConnectionProvider

If the target application is standalone and cannot use the two options above, Hibernate provides the ConnectionProvider interface to integrate with a third-party JDBC connection provider. Users need to implement this interface and then specify the implementation class to Hibernate.

The ConnectionProvider interface has changed with different Hibernate versions. As of Hibernate 4.x, the interface is org.hibernate.engine.jdbc.connections.spi.ConnectionProvider. We will use that version for illustration.

The following is an example implementation of ConnectionProvider that plugs in a UCP data source. It has been tested using Hibernate 4.3.8. Note that the Hibernate 4.x version of the interface no longer provides the configure(Properties hibernateProperties) method, so this example simply overrides the DriverManagerConnectionProviderImpl which provides a similar method. An alternative is for the interface implementation to load the configuration properties from its own properties file or explicitly from the hibernate.properties file.

/* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. */
package oracle.ucp.hibernate.sample;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.logging.Logger;
import oracle.ucp.UniversalConnectionPoolException;
import oracle.ucp.admin.UniversalConnectionPoolManager;
import oracle.ucp.admin.UniversalConnectionPoolManagerImpl;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
public class UCPConnectionProvider
extends DriverManagerConnectionProviderImpl {
private PoolDataSource pds;
private static final Logger logger =
Logger.getLogger(UCPConnectionProvider.class.getCanonicalName());
private static final String URL = "hibernate.ucp.url";
private static final String USER = "hibernate.ucp.user";
private static final String PASSWORD = "hibernate.ucp.password";
private static final String CONN_FACTORY = "hibernate.ucp.connectionFactoryClassName";
private static final String POOL_NAME = "hibernate.ucp.connectionPoolName";
private static final String MAX_POOL_SIZE = "hibernate.ucp.maxPoolSize";
private static final String MIN_POOL_SIZE = "hibernate.ucp.minPoolSize";
private static final String INITIAL_POOL_SIZE = "hibernate.ucp.initialPoolSize";
private static final String FAN_ENABLED = "hibernate.ucp.fastConnectionFailoverEnabled";
private static final String ONS_CONFIG = "hibernate.ucp.onsConfiguration";
private static final String CONN_VALIDATE = "hibernate.ucp.validateConnectionOnBorrow";
public UCPConnectionProvider() {
try {
pds = PoolDataSourceFactory.getPoolDataSource();
logger.finest("PoolDataSource initialized: " + pds);
} catch (Exception exc) {
logger.warning(getStackTraceString(exc));
}
}
public void configure(Map props) throws HibernateException {
if(pds == null)
throw new HibernateException("PoolDataSource was not initialized.");
if (props == null)
throw new HibernateException("Null configuration properties passed in.");
try {
logger.finest("Passed in properties: " + props);
String tempval = (String) props.get(CONN_FACTORY);
if (tempval != null)
pds.setConnectionFactoryClassName(tempval);
tempval = (String) props.get(URL);
if (tempval != null)
pds.setURL(tempval);
tempval = (String) props.get(USER);
if (tempval != null)
pds.setUser(tempval);
tempval = (String) props.get(PASSWORD);
if (tempval != null)
pds.setPassword(tempval);
tempval = (String) props.get(POOL_NAME);
if (tempval != null)
pds.setConnectionPoolName(tempval);
tempval = (String) props.get(MAX_POOL_SIZE);
if (tempval != null)
pds.setMaxPoolSize(Integer.parseInt(tempval));
tempval = (String) props.get(MIN_POOL_SIZE);
if (tempval != null)
pds.setMinPoolSize(Integer.parseInt(tempval));
tempval = (String) props.get(INITIAL_POOL_SIZE);
if (tempval != null)
pds.setInitialPoolSize(Integer.parseInt(tempval));
tempval = (String) props.get(FAN_ENABLED);
if (tempval != null)
pds.setFastConnectionFailoverEnabled(Boolean.parseBoolean(tempval));
tempval = (String) props.get(ONS_CONFIG);
if (tempval != null)
pds.setONSConfiguration(tempval);
tempval = (String) props.get(CONN_VALIDATE);
if (tempval != null)
pds.setValidateConnectionOnBorrow(Boolean.parseBoolean(tempval));
} catch (SQLException sqlexc) {
logger.warning(getStackTraceString(sqlexc));
}
}
public Connection getConnection() throws SQLException {
final Connection conn = pds.getConnection();
logger.finest("Got connection " + conn + " from " + pds +
", number of available connections = " +
pds.getAvailableConnectionsCount() +
", borrowed connections = " +
pds.getBorrowedConnectionsCount());
return conn;
}
public void closeConnection(Connection conn) throws SQLException {
conn.close();
logger.finest("Closed connection " + conn + " from " + pds +
", number of available connections = " +
pds.getAvailableConnectionsCount() +
", borrowed connections = " +
pds.getBorrowedConnectionsCount());
}
public void close() {
try {
final UniversalConnectionPoolManager mgr =
UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager();
mgr.destroyConnectionPool(pds.getConnectionPoolName());
logger.finest("Closed PoolDataSource " + pds);
} catch (UniversalConnectionPoolException exc) {
logger.warning(getStackTraceString(exc));
}
}
public boolean supportsAggressiveRelease() {
return true;
}
public boolean isUnwrappableAs(Class cls) {
return false;
}
public <T> T unwrap(Class<T> cls) {
return null;
}
private String getStackTraceString(Throwable exc)
{
final Writer stackTraceWriter = new StringWriter(1024);
final PrintWriter pw = new PrintWriter(stackTraceWriter);
exc.printStackTrace(pw);
return stackTraceWriter.toString();
}
}

With UCP ConnectionProvider implementation ready, application can declaratively specify the implementation class name using the Hibernate property "hibernate.connection.provider_class".

Below is an example hibernate.cfg.xml file including the UCP-specific configuration properties:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!-- Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. -->
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.provider_class">
oracle.ucp.hibernate.sample.UCPConnectionProvider
</property>
<property name="hibernate.ucp.url">
jdbc:oracle:thin:@//host:1521/service_name
</property>
<property name="hibernate.ucp.connectionFactoryClassName">
oracle.jdbc.pool.OracleDataSource
</property>
<property name="hibernate.ucp.user">scott</property>
<property name="hibernate.ucp.password">tiger</property>
<property name="hibernate.ucp.maxPoolSize">2</property>
</session-factory>
</hibernate-configuration>


Conclusion

In this article, we illustrated three options for using UCP with Hibernate. In all three cases, UCP will function as the connection pool for Hibernate’s JDBC connections and intercept JDBC connection checkouts and checkins without additional application code changes. This allows applications to utilize UCP’s full pooling capabilities including all the scalability and high-availability features for Oracle RAC, ADG, and GDS.



Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.