Configure c3p0 with Hibernate and Spring

By default, Hibernate uses JDBC connections in order to interact with a database. Creating the database connections is expensive, probably the most expensive operation Hibernate executes in a typical usecase. For this reason, we are advised to use a connection pool that can store the opened connections ahead of time and close them only when they are not needed.

Thankfully, Hibernate is designed to use a connection pool by default, an internal implementation. However, Hibernate’s built-in connection pooling isn’t designed for production use. In production, we would use an external connection pool by using either a database connection provided by JNDI or an external connection pool configured via parameters and classpath.

C3P0 is an example of an external connection pool. In this tutorial, we will learn to use C3P0 with Hibernate 6.

1. Maven Dependencies

To configure c3p0 with hibernate, we need to add Hibernate’s c3p0 connection provider hibernate-c3p0 as dependency in the pom.xml. Please note that the version of the hibernate-c3p0 dependency should match Hibernate’s compatible version.

The hibernate-c3p0 transitively includes the com.mchange:c3p0 in build time.

<dependency>
    <groupId>org.hibernate.orm</groupId>
    <artifactId>hibernate-c3p0</artifactId>
    <version>6.0.0.Final</version>
</dependency>

2. C3P0 Configuration with Hibernate

The best part is that the whole configuration of C3P0 with hibernate is really very easy. In most cases, if we do not have any other connection provider, just adding any hibernate.c3p0.x property inside the hibernate.cfg.xml file will configure it with defaults.

<property name="hibernate.c3p0.min_size">10</property>

Connection pooling with C3P0 is now configured. We are good to start testing things. Really easy, Isn’t it?

If there is more than one connection pool then to enforce c3p0 poling, we can provide the provider_class property.

<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

A rather detailed configuration can be setup using the following properties in hibernate.cfg.xml. All keys are prefixed with hibernate.c3p0.

<property name="hibernate.c3p0.min_size">10</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.acquire_increment">1</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.timeout">1800</property>
<property name="hibernate.c3p0.validate">1800</property>

We can find detailed information about the above configuration switches in the official documentation.

3. Configuring with Spring

In Spring ORM, we can supply the hibernate properties either using hibernate.cfg.xml or a @Configuration class. Let us see an example of both.

3.1. Java Configuration

The following HibernateConfig class is an example spring configuration class that registers the necessary beans for hibernate, including the transaction manager.

@Configuration
@EnableTransactionManagement
@ComponentScans(value = {@ComponentScan("com.howtodoinjava.demo.spring")})
public class HibernateConfig {

  @Autowired
  private ApplicationContext context;

  @Bean
  public LocalSessionFactoryBean getSessionFactory() {

    LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
    factoryBean.setPackagesToScan("com.howtodoinjava.demo.spring.model");

    Properties properties = new Properties();

    //c3p0 specific properties
    properties.putAll(Map.of(
        "hibernate.c3p0.min_size", "5",
        "hibernate.c3p0.max_size", "20",
        "hibernate.c3p0.acquire_increment", "2",
        "hibernate.c3p0.max_statements", "150",
        "hibernate.c3p0.timeout", "1800"
    ));

    //hibernate properties
    properties.putAll(Map.of(
        "hibernate.connection.provider_class", "org.hibernate.connection.C3P0ConnectionProvider",
        "hibernate.connection.username", "sa",
        "hibernate.connection.password", "password",
        "hibernate.connection.url", "jdbc:h2:mem:testdb",
        "hibernate.dialect", "org.hibernate.dialect.H2Dialect",
        "hibernate.connection.driver_class", "org.h2.Driver",
        "hibernate.hbm2ddl.auto", "create-drop",
        "hibernate.archive.autodetection", "class,hbm",
        "hibernate.show_sql", "true"
    ));

    factoryBean.setHibernateProperties(properties);
    return factoryBean;
  }

  @Bean
  public HibernateTransactionManager getTransactionManager() {

    HibernateTransactionManager transactionManager = new HibernateTransactionManager();
    transactionManager.setSessionFactory(getSessionFactory().getObject());
    return transactionManager;
  }
}

3.2. XML Configuration

In case, we want to configure the properties in an XML file and use it for initializing the beans, we need to change the LocalSessionFactoryBean definition as follows:

@Bean
public LocalSessionFactoryBean getSessionFactory() {

  LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
  factoryBean.setPackagesToScan("com.howtodoinjava.demo.spring.model");
  factoryBean.setConfigLocation(context.getResource("classpath:hibernate.cfg.xml"));
  return factoryBean;
}

And put the hibernate.cfg.xml file in ‘/src/main/resources’ directory.

<?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">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
    <property name="hibernate.archive.autodetection">class,hbm</property>
    <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.connection.driver_class">org.h2.Driver</property>
    <property name="hibernate.connection.username">sa</property>
    <property name="hibernate.connection.password">password</property>
    <property name="hibernate.connection.url">jdbc:h2:mem:testdb</property>
    <property name="hibernate.hbm2ddl.auto">create-drop</property>
    <property name="hibernate.packageToScan">com.howtodoinjava.demo.spring.model</property>

    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.max_size">20</property>
    <property name="hibernate.c3p0.acquire_increment">2</property>
    <property name="hibernate.c3p0.acquire_increment">1800</property>
    <property name="hibernate.c3p0.max_statements">150</property>
  </session-factory>
</hibernate-configuration>

4. Debugging Connection Leaks

Sometimes applications talk to many other applications and some applications or interactions take a longer time to respond. This can overwhelm the connection pool (when the pool grows to maxPoolSize) and degrade the performance of the whole application.

c3p0 can help us debug the pool where connections have been checked out and don’t get checked in.

<property name="hibernate.c3p0.unreturnedConnectionTimeout">30</property>
<property name="hibernate.c3p0.debugUnreturnedConnectionStackTraces">true</property>
  • unreturnedConnectionTimeout helps in fixing leaks. It defines the time (in seconds) to how long a Connection may remain checked out. Checked-out Connections that exceed this limit will be destroyed, and then created a new one in the pool.
  • debugUnreturnedConnectionStackTraces helps in debugging the root cause. when set to true, whenever an unreturned Connection times out, that stack trace will be printed, revealing where a Connection was checked out that was not checked in.

5. Demo

5.1. Application Logs Without C3P0 Configuration

Without C3P0 configured, if you see the debug logs of hibernate, we will see something like this:

DEBUG Configuration:1841 - Preparing to build session factory with filters : {}
WARN DriverManagerConnectionProviderImpl:93 - HHH000402: Using Hibernate built-in connection pool (not for production use!)
INFO DriverManagerConnectionProviderImpl:166 - HHH000401: using driver [org.hsqldb.jdbcDriver] at URL [jdbc:hsqldb:mem:howtodoinjava]
INFO DriverManagerConnectionProviderImpl:172 - HHH000046: Connection properties: {user=sa, password=}
INFO DriverManagerConnectionProviderImpl:180 - HHH000006: Autocommit mode: false
INFO DriverManagerConnectionProviderImpl:102 - HHH000115: Hibernate connection pool size: 20 (min=1)
DEBUG DriverManagerConnectionProviderImpl:104 - Initializing Connection pool with 1 Connections
...
...
...
EBUG JdbcTransaction:113 - committed JDBC Connection
DEBUG SessionFactoryImpl:1339 - HHH000031: Closing
DEBUG AbstractServiceRegistryImpl:406 - Implicitly destroying ServiceRegistry on de-registration of all child ServiceRegistries
INFO DriverManagerConnectionProviderImpl:281 - HHH000030: Cleaning up connection pool [jdbc:hsqldb:mem:howtodoinjava]

5.2. Application Logs With C3P0 Configuration

After configuring C3P0 Connection Pool, you will be able to see in the logs that connections are now acquired from C3P0 Connection Pool itself.

DEBUG Configuration:1841 - Preparing to build session factory with filters : {}
 INFO C3P0ConnectionProvider:133 - HHH010002: C3P0 using driver: org.hsqldb.jdbcDriver at URL: jdbc:hsqldb:mem:howtodoinjava
 INFO C3P0ConnectionProvider:134 - HHH000046: Connection properties: {user=sa, password=****}
 INFO C3P0ConnectionProvider:137 - HHH000006: Autocommit mode: false
 INFO MLog:92 - MLog clients using log4j logging.
 INFO C3P0Registry:216 - Initializing c3p0-0.9.2.1 [built 20-March-2013 10:47:27 +0000; debug? true; trace: 10]
DEBUG DynamicPooledDataSourceManagerMBean:258 - MBean: com.mchange.v2.c3p0:type=PooledDataSource,identityToken=19tu9of94ho8s13xij3fm|34e475e1,name=19tu9of94ho8s13xij3fm|34e475e1 registered.
DEBUG DynamicPooledDataSourceManagerMBean:253 - MBean: com.mchange.v2.c3p0:type=PooledDataSource,identityToken=19tu9of94ho8s13xij3fm|34e475e1,name=19tu9of94ho8s13xij3fm|34e475e1 unregistered, in order to be reregistered after update.
DEBUG DynamicPooledDataSourceManagerMBean:258 - MBean: com.mchange.v2.c3p0:type=PooledDataSource,identityToken=19tu9of94ho8s13xij3fm|34e475e1,name=19tu9of94ho8s13xij3fm|34e475e1 registered.
 INFO AbstractPoolBackedDataSource:522 - Initializing c3p0 pool... com.mchange.v2.c3p0.PoolBackedDataSource@d29bbf50 [ connectionPoolDataSource -&gt; com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@a9bbd924 [ ... ]
 ...
 ...
 ...
 DEBUG ActiveManagementCoordinator:97 - C3P0Registry mbean unregistered.
DEBUG BasicResourcePool:1022 - Preparing to destroy resource: com.mchange.v2.c3p0.impl.NewPooledConnection@1d1fcfbb
DEBUG C3P0PooledConnectionPool:616 - Preparing to destroy PooledConnection: com.mchange.v2.c3p0.impl.NewPooledConnection@1d1fcfbb
DEBUG AbstractPoolBackedDataSource:477 - com.mchange.v2.c3p0.PoolBackedDataSource@34e475e1 has been closed.
java.lang.Exception: DEBUG STACK TRACE for PoolBackedDataSource.close().

That’s all for this easy but useful tutorial about configuring C3P0 Connection Pool with hibernate 6.

Happy Learning !!

Source Code on Github

Comments are closed for this article!

Comments

6 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

Comments are closed for this article!

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.