Hibernate Batch Processing Tutorial with examples

Consider a situation when you need to upload a large number of records into your database using Hibernate. Following is the code snippet to achieve this using Hibernate:
Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
    Employee employee = new Employee(.....);
    session.save(employee);
}
tx.commit();
session.close();

Because by default, Hibernate will cache all the persisted objects in the session-level cache and ultimately your application would fall over with an OutOfMemoryException somewhere around the 50,000th row. You can resolve this problem if you are using batch processing with Hibernate.

To use the batch processing feature, first set hibernate.jdbc.batch_size as batch size to a number either at 20 or 50 depending on object size. This will tell the hibernate container that every X rows to be inserted as batch. To implement this in your code we would need to do little modification as follows:

Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
    Employee employee = new Employee(.....);
    session.save(employee);
 if( i % 50 == 0 ) { // Same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}
tx.commit();
session.close();

Above code will work fine for the INSERT operation, but if you are willing to make UPDATE operation then you can achieve using the following code:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

ScrollableResults employeeCursor = session.createQuery("FROM EMPLOYEE")
                                   .scroll();
int count = 0;

while ( employeeCursor.next() ) {
   Employee employee = (Employee) employeeCursor.get(0);
   employee.updateEmployee();
   seession.update(employee); 
   if ( ++count % 50 == 0 ) {
      session.flush();
      session.clear();
   }
}
tx.commit();
session.close();

Batch Processing Example:

To use the batch processing feature, first set hibernate.jdbc.batch_size as 50. This will tell the hibernate container that every 50 rows to be inserted as batch. Also there is a slight change in the code.
<?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.driver_class">net.sourceforge.jtds.jdbc.Driver</property>
        <property name="hibernate.connection.password">password</property>
        <property name="hibernate.connection.url">jdbc:jtds:sqlserver://localhost:1433/SBMUATDB</property>
        <property name="hibernate.connection.username">username</property>
        <property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
     <property name="connection.pool_size">1</property>
        <property name="hbm2ddl.auto">create</property>
        <property name="show_sql">false</property>  
  <property name="format_sql">true</property>    
  <property name="hibernate.jdbc.batch_size">50</property>
  <mapping class="com.tutorialsdesk.hibernate.bean.Employee"/>

    </session-factory>
</hibernate-configuration>



Consider the following POJO Employee class:
package com.tutorialsdesk.hibernate.bean;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;


@Entity 
@Table(name="EMPLOYEE",uniqueConstraints = { @UniqueConstraint(columnNames = "id") }) 

public class Employee {
 @Id   
 @GeneratedValue(strategy = GenerationType.AUTO)
 @Column(name = "id")  
 private int id;
 
 @Column(name="first_name")  
 private String firstName;
 
 @Column(name="last_name")  
 private String lastName;
 
 @Column(name="salary")  
 private int salary;
 
 
 
 public Employee() {
  
 }
 
 public Employee(String firstName, String lastName, int salary) {
  super();
  this.firstName = firstName;
  this.lastName = lastName;
  this.salary = salary;
 }
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getFirstName() {
  return firstName;
 }
 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }
 public String getLastName() {
  return lastName;
 }
 public void setLastName(String lastName) {
  this.lastName = lastName;
 }
 public int getSalary() {
  return salary;
 }
 public void setSalary(int salary) {
  this.salary = salary;
 }
}


Let us create the following EMPLOYEE table to store Employee objects:
create table EMPLOYEE (
   id INT NOT NULL Identity PRIMARY KEY,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
)

Finally, we will create our application class with the main() method to run the application where we will use flush() and clear() methods available with Session object so that Hibernate keep writing these records into the database instead of caching them in the memory.

package com.tutorialsdesk.hibernate;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;

import com.tutorialsdesk.hibernate.bean.Employee;

public class ManageEmployee {

 private static SessionFactory factory; 
    public static void main(String[] args) {
       try{
          factory = new AnnotationConfiguration().configure().buildSessionFactory(); 
       }catch (Throwable ex) { 
          System.err.println("Failed to create sessionFactory object." + ex);
          throw new ExceptionInInitializerError(ex); 
       }
       ManageEmployee ME = new ManageEmployee();

       /* Add employee records in batches */
       ME.addEmployees( );
    }
    /* Method to create employee records in batches */
    public void addEmployees( ){
       Session session = factory.openSession();
       Transaction tx = null;
       Integer employeeID = null;
       try{
          tx = session.beginTransaction();
          for ( int i=0; i<100000; i++ ) {
             String fname = "First Name " + i;
             String lname = "Last Name " + i;
             Integer salary = i;
             Employee employee = new Employee(fname, lname, salary);
             session.save(employee);
           if( i % 50 == 0 ) {
            System.out.println("Flushed to DB");
                session.flush();
                session.clear();
             }
          }
          tx.commit();
       }catch (HibernateException e) {
          if (tx!=null) tx.rollback();
          e.printStackTrace(); 
       }finally {
          session.close(); 
       }
       return ;
    }

}

Hibernate Batch Processing Tutorial with examples