Merge vs Update in Hibernate with example


Let us understand Merge and Update in Hibernate


The most important and frequently asked question in Hibernate is the difference between merge and update methods and often we can notice that developers use update() and merge() methods alternatively.

Let’s understand the use of merge() and update() methods with example


We know that both merge() and update() methods are used to update the entity and can also change the state of an object(from detached to persistent state).

Please read this article to know about different states of an object in Hibernate.

But there is a subtle difference between update() and merge() methods.

The difference is update() method can not be used when the same object already exist in the session whereas merge() method can be used.

Lets see how update() method works with example


update

When we call update() method, if the same object is not exist in session cache then the update() method will update the object.

When we call update() method, if the same object is already exist in session cache then the update() method throws an exception called “NonUniqueObjectException”.

Lets see how merge() method works with example


merge

Similar to update() method, merge() method also changes the state of detached state to persistent state.

When we call merge() method, It first checks the same object exist in cache
If exist then it will update the cache with the changes, else if object is not exist in cache then it will load the values to cache.

So in either way,unlike update() method, merge() method will not throw any exception.

Let’s understand merge() and update() with sample project

Step 1

Create hibernate project

Please refer Hibernate setup in eclipse article on how to do it.

Project structure


hibernate_update_merge_proj_stru

Step 2

Update pom.xml with Hibernate and Mysql dependencies

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
32
33
34
35
36
37
38
39
40
41
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>HibernateMergeUpdate</groupId>
  <artifactId>HibernateMergeUpdate</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>HibernateMergeUpdate</name>
  <url>http://maven.apache.org</url>
 
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
 
  <dependencies>
 
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
 
    <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.2.6.Final</version>
    </dependency>
 
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>6.0.5</version>
    </dependency>
 
  </dependencies>
 
</project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>HibernateMergeUpdate</groupId>
  <artifactId>HibernateMergeUpdate</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>HibernateMergeUpdate</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

    <dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-core</artifactId>
	<version>5.2.6.Final</version>
    </dependency>

	<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>6.0.5</version>
    </dependency>

  </dependencies>

</project>

Step 3

Create Employee class

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.kb.model;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
 
@Entity
@Table(name="Employee")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "Employee_Id")
    private int employeeId;
    
    @Column(name = "FirstName")
    private String firstName;
    
    @Column(name = "LastName")
    private String lastName;
    
    @Column(name = "Age")
    private int age;
    
    @Column(name = "Education")
    private String education;
    
    @Column(name = "Salary")
    private int salary;
    
    public int getEmployeeId() {
        return employeeId;
    }
    public void setEmployeeId(int employeeId) {
        this.employeeId = employeeId;
    }
    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 getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getEducation() {
        return education;
    }
    public void setEducation(String education) {
        this.education = education;
    }
    public int getSalary() {
        return salary;
    }
    public void setSalary(int salary) {
        this.salary = salary;
    }
}
package com.kb.model;

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

@Entity
@Table(name="Employee")
public class Employee {
	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE)
	@Column(name = "Employee_Id")
	private int employeeId;
	
	@Column(name = "FirstName")
	private String firstName;
	
	@Column(name = "LastName")
	private String lastName;
	
	@Column(name = "Age")
	private int age;
	
	@Column(name = "Education")
	private String education;
	
	@Column(name = "Salary")
	private int salary;
	
	public int getEmployeeId() {
		return employeeId;
	}
	public void setEmployeeId(int employeeId) {
		this.employeeId = employeeId;
	}
	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 getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getEducation() {
		return education;
	}
	public void setEducation(String education) {
		this.education = education;
	}
	public int getSalary() {
		return salary;
	}
	public void setSalary(int salary) {
		this.salary = salary;
	}
}


We have specified Primary key as employeeId and generator class as “sequence” for automatic primary key generation.

Step 4

Create hibernate.cfg.xml

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
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
       "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
       "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
 
<hibernate-configuration>
 
    <session-factory>
 
        <!-- Database connection properties -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost/javainsimpleway</property>
        <property name="connection.username">root</property>
        <property name="connection.password">root</property>
 
        <!-- JDBC connection pool (using the built-in) -->
        <property name="connection.pool_size">100</property>
 
        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
 
        <!-- Disable the second-level cache -->
        <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
 
        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>
 
        <!-- Format the generated Sql -->
        <property name="format_sql">true</property>
 
        <!-- Dont Drop and re-create the database schema on startup,Just update 
            it -->
        <property name="hbm2ddl.auto">update</property>
 
        <mapping class="com.kb.model.Employee" />
 
    </session-factory>
 
</hibernate-configuration>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
       "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
       "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

	<session-factory>

		<!-- Database connection properties -->
		<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="connection.url">jdbc:mysql://localhost/javainsimpleway</property>
		<property name="connection.username">root</property>
		<property name="connection.password">root</property>

		<!-- JDBC connection pool (using the built-in) -->
		<property name="connection.pool_size">100</property>

		<!-- SQL dialect -->
		<property name="dialect">org.hibernate.dialect.MySQLDialect</property>

		<!-- Disable the second-level cache -->
		<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>

		<!-- Echo all executed SQL to stdout -->
		<property name="show_sql">true</property>

		<!-- Format the generated Sql -->
		<property name="format_sql">true</property>

		<!-- Dont Drop and re-create the database schema on startup,Just update 
			it -->
		<property name="hbm2ddl.auto">update</property>

		<mapping class="com.kb.model.Employee" />

	</session-factory>

</hibernate-configuration>


We have defined all the database configuration in this file

hbm2ddl.auto property is defined in the config file which helps in automatic creation of tables in the database based on the mapping.

We have also provided the mapping class name using “mapping” tag.

Step 5

Create Hibernate util class

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
package com.kb.util;
 
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
public class HibernateUtil {
    private static final SessionFactory sessionFactory = buildSessionFactory();
 
    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Make sure you log the exception to track it
            System.err.println("SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
 
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    
    public static void shutdown() {
        // Optional but can be used to Close caches and connection pools
        getSessionFactory().close();
    }
 
}
package com.kb.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
	private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Make sure you log the exception to track it
            System.err.println("SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    
    public static void shutdown() {
    	// Optional but can be used to Close caches and connection pools
    	getSessionFactory().close();
    }

}

Step 6

Create PopulateData.java file to Populate Employee Table with initial data

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.kb.db;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
 
import com.kb.model.Employee;
import com.kb.util.HibernateUtil;
 
public class PopulateData {
public static void main(String[] args) {
 
    // Get session factory using Hibernate Util class
    SessionFactory sf = HibernateUtil.getSessionFactory();
    // Get session from Sesson factory
    Session session = sf.openSession();
 
    // Begin transaction
    Transaction t = session.beginTransaction();
    
    //Create Employee  data
    Employee employee1 = new Employee();
    employee1.setFirstName("John");
    employee1.setLastName("KC");
    employee1.setAge(28);
    employee1.setEducation("PG");
    employee1.setSalary(25000);
    
    Employee employee2 = new Employee();
    employee2.setFirstName("Jacob");
    employee2.setLastName("JC");
    employee2.setAge(30);
    employee2.setEducation("PG");
    employee2.setSalary(30000);
    
    Employee employee3 = new Employee();
    employee3.setFirstName("Martin");
    employee3.setLastName("A");
    employee3.setAge(24);
    employee3.setEducation("UG");
    employee3.setSalary(20000);
    
    Employee employee4 = new Employee();
    employee4.setFirstName("Peter");
    employee4.setLastName("M");
    employee4.setAge(25);
    employee4.setEducation("UG");
    employee4.setSalary(22000);
    
    Employee employee5 = new Employee();
    employee5.setFirstName("Roshan");
    employee5.setLastName("B");
    employee5.setAge(29);
    employee5.setEducation("PG");
    employee5.setSalary(45000);
    
    
    session.save(employee1);
    session.save(employee2);
    session.save(employee3);
    session.save(employee4);
    session.save(employee5);
 
    // Commit the transaction and close the session
    t.commit();
    
    session.close();
    System.out.println("successfully persisted Employee details");
 
   }
 
}
package com.kb.db;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.kb.model.Employee;
import com.kb.util.HibernateUtil;

public class PopulateData {
public static void main(String[] args) {

	// Get session factory using Hibernate Util class
	SessionFactory sf = HibernateUtil.getSessionFactory();
	// Get session from Sesson factory
	Session session = sf.openSession();

	// Begin transaction
	Transaction t = session.beginTransaction();
	
	//Create Employee  data
	Employee employee1 = new Employee();
	employee1.setFirstName("John");
	employee1.setLastName("KC");
	employee1.setAge(28);
	employee1.setEducation("PG");
	employee1.setSalary(25000);
	
	Employee employee2 = new Employee();
	employee2.setFirstName("Jacob");
	employee2.setLastName("JC");
	employee2.setAge(30);
	employee2.setEducation("PG");
	employee2.setSalary(30000);
	
	Employee employee3 = new Employee();
	employee3.setFirstName("Martin");
	employee3.setLastName("A");
	employee3.setAge(24);
	employee3.setEducation("UG");
	employee3.setSalary(20000);
	
	Employee employee4 = new Employee();
	employee4.setFirstName("Peter");
	employee4.setLastName("M");
	employee4.setAge(25);
	employee4.setEducation("UG");
	employee4.setSalary(22000);
	
	Employee employee5 = new Employee();
	employee5.setFirstName("Roshan");
	employee5.setLastName("B");
	employee5.setAge(29);
	employee5.setEducation("PG");
	employee5.setSalary(45000);
	
	
	session.save(employee1);
	session.save(employee2);
	session.save(employee3);
	session.save(employee4);
	session.save(employee5);

	// Commit the transaction and close the session
	t.commit();
	
	session.close();
	System.out.println("successfully persisted Employee details");

   }

}


In this class, we are persisting 5 Employee records

Step 7

Lets Create Main class to perform Update and Merge operations

UpdateExample1.java

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
package com.kb.db;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
 
import com.kb.model.Employee;
import com.kb.util.HibernateUtil;
 
public class UpdateExample1 {
    public static void main(String[] args) {
        // Get session factory using Hibernate Util class
        SessionFactory sf = HibernateUtil.getSessionFactory();
        // Get session from Session factory
        Session session1 = sf.openSession();
 
        // Load the Employee details whose Id is 1
        Employee employee = (Employee) session1.get(Employee.class, new Integer(1));
        
        session1.close();
        
        //Update employee object, which is in detached state
        employee.setAge(45);
        
        Session session2 = sf.openSession();
        Transaction tx = session2.beginTransaction();
        session2.update(employee);
        tx.commit();
    }
 
}
package com.kb.db;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.kb.model.Employee;
import com.kb.util.HibernateUtil;

public class UpdateExample1 {
	public static void main(String[] args) {
		// Get session factory using Hibernate Util class
		SessionFactory sf = HibernateUtil.getSessionFactory();
		// Get session from Session factory
		Session session1 = sf.openSession();

		// Load the Employee details whose Id is 1
		Employee employee = (Employee) session1.get(Employee.class, new Integer(1));
		
		session1.close();
		
		//Update employee object, which is in detached state
		employee.setAge(45);
		
		Session session2 = sf.openSession();
		Transaction tx = session2.beginTransaction();
        session2.update(employee);
        tx.commit();
	}

}


In this program, we are updating the age to 45 for an employee whose id is 1.

In this program, employee object in detached state is attached again to session to make it persistent and cache will not have the object with same id

Hence update will be successful in this case.

Create UpdateExample2.java

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
32
33
package com.kb.db;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
 
import com.kb.model.Employee;
import com.kb.util.HibernateUtil;
 
public class UpdateExample2 {
    public static void main(String[] args) {
        // Get session factory using Hibernate Util class
        SessionFactory sf = HibernateUtil.getSessionFactory();
        // Get session from Session factory
        Session session1 = sf.openSession();
 
        // Load the Employee details whose Id is 1
        Employee employee1 = (Employee) session1.get(Employee.class, new Integer(1));
        
        session1.close();
        
        //Update employee object, which is in detached state
        employee1.setAge(50);
        
        Session session2 = sf.openSession();
        Employee employee2 = (Employee) session2.get (Employee.class, new Integer(1));
        Transaction tx = session2.beginTransaction();
        System.out.println(employee1==employee2);
        session2.update(employee1);
        tx.commit();
    }
 
}
package com.kb.db;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.kb.model.Employee;
import com.kb.util.HibernateUtil;

public class UpdateExample2 {
	public static void main(String[] args) {
		// Get session factory using Hibernate Util class
		SessionFactory sf = HibernateUtil.getSessionFactory();
		// Get session from Session factory
		Session session1 = sf.openSession();

		// Load the Employee details whose Id is 1
		Employee employee1 = (Employee) session1.get(Employee.class, new Integer(1));
		
		session1.close();
		
		//Update employee object, which is in detached state
		employee1.setAge(50);
		
		Session session2 = sf.openSession();
		Employee employee2 = (Employee) session2.get (Employee.class, new Integer(1));
		Transaction tx = session2.beginTransaction();
		System.out.println(employee1==employee2);
        session2.update(employee1);
        tx.commit();
	}

}


In this program, we are updating the age to 50 for an employee whose id is 1.

In this program, employee object in detached state is attached again to session to make it persistent and then we are loading again the employee with same id using session2

Hence it will be added in session cache, so updating detached object will fail in this case as object with same id is already exist in cache, as a result of it below exception has thrown.

Exception in thread “main” org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.kb.model.Employee#1]

Create MergeExample.java

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
32
33
package com.kb.db;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
 
import com.kb.model.Employee;
import com.kb.util.HibernateUtil;
 
public class MergeExample {
    public static void main(String[] args) {
        // Get session factory using Hibernate Util class
        SessionFactory sf = HibernateUtil.getSessionFactory();
        // Get session from Session factory
        Session session1 = sf.openSession();
 
        // Load the Employee details whose Id is 1
        Employee employee1 = (Employee) session1.get(Employee.class, new Integer(1));
        
        session1.close();
        
        //Update employee object, which is in detached state
        employee1.setAge(55);
        
        Session session2 = sf.openSession();
        Employee employee2 = (Employee) session2.get(Employee.class, new Integer(1));
        Transaction tx = session2.beginTransaction();
        System.out.println(employee1==employee2);
        session2.merge(employee1);
        tx.commit();
    }
 
}
package com.kb.db;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.kb.model.Employee;
import com.kb.util.HibernateUtil;

public class MergeExample {
	public static void main(String[] args) {
		// Get session factory using Hibernate Util class
		SessionFactory sf = HibernateUtil.getSessionFactory();
		// Get session from Session factory
		Session session1 = sf.openSession();

		// Load the Employee details whose Id is 1
		Employee employee1 = (Employee) session1.get(Employee.class, new Integer(1));
		
		session1.close();
		
		//Update employee object, which is in detached state
		employee1.setAge(55);
		
		Session session2 = sf.openSession();
		Employee employee2 = (Employee) session2.get(Employee.class, new Integer(1));
		Transaction tx = session2.beginTransaction();
		System.out.println(employee1==employee2);
        session2.merge(employee1);
        tx.commit();
	}

}


In this program, we are updating the age to 55 for an employee whose id is 1.

In this program, employee object in detached state is attached again to session to make it persistent and then we are loading again the employee with same id using session2

Hence it will be added in session cache, so updating detached object will fail in this case as object with same id is already exist in cache,
But merge will copy the changes into the cache and hence exception will not be thrown.

Step 8

Run PopulateData.java class to create the initial data

Step 9

Check the output in MYSQL DB

E:\MySql_Install\bin
Mysql –u root –p
Enter password

Use javainsimpleway;

Select * from Employee;

populateAggregateDataOutput

We can see that Emploeyee table has 5 records.

Step 10

Run UpdateExample1.java

Output

hibernate_update_1_output

We can see that,employee whose id is ‘1’ is updated with age ’45’

Step 11

Run UpdateExample2.java

Output

hibernate_update_2_output

Step 12

Run MergeExample.java

Output

hibernate_merge_output

We can see that,employee whose id is ‘1’ is updated with age ’55’

Note:
If the object already exist in cache then update() method will throw exception where as merge() method copies the updated changes in to cache and it wont throw any exception.


Download this project HibernateMergeUpdate.zip

About the Author

Karibasappa G C (KB)
Founder of javainsimpleway.com
I love Java and open source technologies and very much passionate about software development.
I like to share my knowledge with others especially on technology 🙂
I have given all the examples as simple as possible to understand for the beginners.
All the code posted on my blog is developed,compiled and tested in my development environment.
If you find any mistakes or bugs, Please drop an email to kb.knowledge.sharing@gmail.com

Connect with me on Facebook for more updates

Share this article on