Thursday May 21, 2015

UCP with Spring Framework

This article illustrates the steps to use Oracle Universal Connection Pool (UCP) with the Spring framework, using a sample application built using the JDBC template.

  • Assume there is a simple table EMP in the database with a single column “name” that is loaded with employee information (i.e., employee names).
  • Consider the following example DAO class in the package “test”:
  • The following is an example of the Row mapper implementation class for the EMP table:
  • The following class is the example of a java class that uses the JDBC Template for implementing the business logic:
  • The XML configuration file should specify UCP's oracle.ucp.jdbc.PoolDataSourceImpl as the data source class along with relevant connection pool properties, such as the initial-pool-size, max-pool-size, etc. For this sample, the XML configuration file is named "HelloAppConf.xml".
    <?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>
  • The main application code looks like the following. The application using the JDBC template will internally use the Universal Connection Pool (UCP) for connection check-outs and check-ins.

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.

Wednesday Oct 09, 2013

Write recovery code with Transaction Guard

This article demonstrates how to use in Java a new 12C database feature called Transaction Guard.[Read More]
About

Phil Wang-Oracle

Search

Categories
Archives
« August 2015
SunMonTueWedThuFriSat
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
     
Today