Hibernate save() and saveOrUpdate() methods

hibernate works only with persistent entities and persistent entities are classes which are attached to any hibernate session. Please note that creating an instance of a class, you mapped with a hibernate annotations, does not automatically persist the object to the database. It must be save explicitly after attaching it to a valid hibernate session.

In this tutorial, learn to use hibernate save() and saveOrUpdate() methods under different usecases.

1. Hibernate save() method

In hibernate, we generally use one of below two versions of save() method:

public Serializable save(Object object) throws HibernateException
public Serializable save(String entityName,Object object) throws HibernateException

Both save() methods take a transient object reference (which must not be null) as an argument. Second method takes an extra parameter ‘entityName‘ which is useful in case you have mapped multiple entities to a Java class. Here you can specify which entity you are saving using save() method.

A simple example to demo hibernate save() method.

@Entity 
@Table(name = "Employee")
public class EmployeeEntity implements Serializable
{
   private static final long serialVersionUID = -1798070786993154676L;
   @Id
   @Column(name = "ID", unique = true, nullable = false)
   private Integer	employeeId;
   
   @Column(name = "FIRST_NAME", unique = false, nullable = false, length = 100)
   private String	firstName;
   
   @Column(name = "LAST_NAME", unique = false, nullable = false, length = 100)
   private String	lastName;
   
   @Override
   public boolean equals(Object o) {
       if (this == o) return true;
       if (!(o instanceof EmployeeEntity)) return false;
    
       EmployeeEntity otherEmployee = (EmployeeEntity) o;
    
       if (getEmployeeId() != null ?
           !getEmployeeId().equals(otherEmployee.getEmployeeId()) : otherEmployee.getEmployeeId() != null)
           return false;
       if (getFirstName() != null ?
           !getFirstName().equals(otherEmployee.getFirstName()) : otherEmployee.getFirstName() != null)
           return false;
       if (getLastName() != null ?
           !getLastName().equals(otherEmployee.getLastName()) : otherEmployee.getLastName() != null)
           return false;
    
       return true;
   }
    
   @Override
   public int hashCode() {
   int result = getEmployeeId() != null ? getEmployeeId().hashCode() : 0;
       result = 31 * result + (getFirstName() != null ? getFirstName().hashCode() : 0);
       result = 31 * result + (getLastName() != null?getLastName().hashCode() : 0);
       return result;
   }
   
   //Getters and Setters are hidden here
}

Now let’s save this hibernate entity.

public class SimplestSaveEntityExample
{
   public static void main(String[] args)
   {
      Session sessionOne = HibernateUtil.getSessionFactory().openSession();
      sessionOne.beginTransaction();
      
      //Create new Employee object
      EmployeeEntity emp = new EmployeeEntity();
      emp.setEmployeeId(1);
      emp.setFirstName("Lokesh");
      emp.setLastName("Gupta");
      
      //Save employee
      sessionOne.save(emp);
      
      sessionOne.getTransaction().commit();
      HibernateUtil.shutdown();
   }    
}

Program Output.

Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)

1.1. Calling save() method on persistent entity

We got our Employee entity saved. So easy. But in reality, it is not so simple usecase. There you may need to update again employee entity and then save again in another session. Should you call save() method again? Let’s check out.

public class SaveEntityAgainInAnotherSession
{
   public static void main(String[] args)
   {
      Session sessionOne = HibernateUtil.getSessionFactory().openSession();
      sessionOne.beginTransaction();
      
      //Create new Employee object
      EmployeeEntity emp = new EmployeeEntity();
      emp.setEmployeeId(1);
      emp.setFirstName("Lokesh");
      emp.setLastName("Gupta");
      
      //Save employee
      sessionOne.save(emp);
      sessionOne.getTransaction().commit();
      
      Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
      sessionTwo.beginTransaction();
      
      emp.setLastName("temp");
      //Save employee again second time
      sessionTwo.save(emp);
      
      sessionTwo.getTransaction().commit();
      HibernateUtil.shutdown();
   }    
}

Program Output.

Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
 WARN SqlExceptionHelper:144 - SQL Error: -104, SQLState: 23000
ERROR SqlExceptionHelper:146 - Violation of unique constraint SYS_PK_49: duplicate value(s) for column(s) ID in statement [insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)]
 INFO AbstractBatchImpl:208 - HHH000010: On release of batch it still contained JDBC statements

Here hibernate tried to insert the entity again. Though it was failed due to primary key check, but check may not be there for other entities and you may end up with duplicate rows.

Note: While second save() method causes duplicate row in different sessions, BUT in same session they will work correct.

Look at below example.

public class SaveEntityAgainInSameSession
{
   public static void main(String[] args)
   {
      Session sessionOne = HibernateUtil.getSessionFactory().openSession();
      sessionOne.beginTransaction();
      
      //Create new Employee object
      EmployeeEntity emp = new EmployeeEntity();
      emp.setEmployeeId(1);
      emp.setFirstName("Lokesh");
      emp.setLastName("Gupta");
      
      //Save employee
      sessionOne.save(emp);
      
      emp.setLastName("temp");
      //Save employee again second time
      sessionOne.save(emp);
      
      sessionOne.getTransaction().commit();
      HibernateUtil.shutdown();
   }    
}

Program Output.

Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
Hibernate: update Employee set FIRST_NAME=?, LAST_NAME=? where ID=?

It’s confusing. Right? Let’s make it simple. And rule is below:

Remember that you should not call save() method on a persistent entity (entity associated with any hibernate session). Any changes done to persistent entity is automatically saved.

1.2. Changing state of persistent entity

Any change to persistent entity is saved automatically. Let’s understand this concept in simple example.

public class NoSaveCallForPersistentEntity
{
   public static void main(String[] args)
   {
      Session sessionOne = HibernateUtil.getSessionFactory().openSession();
      sessionOne.beginTransaction();
      
      //Create new Employee object
      EmployeeEntity emp = new EmployeeEntity();
      emp.setEmployeeId(1);
      emp.setFirstName("Lokesh");
      emp.setLastName("Gupta");
      
      //Save employee
      sessionOne.save(emp);
      
      emp.setLastName("temp");
      
      sessionOne.getTransaction().commit();
      
      //Let's see what got updated in DB
      Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
      sessionTwo.beginTransaction();
      
      EmployeeEntity employee = ( EmployeeEntity ) sessionTwo.load(EmployeeEntity.class, 1);
      System.out.println(employee.getLastName());
      
      sessionTwo.getTransaction().commit();
      HibernateUtil.shutdown();
   }    
}

Program Output.

Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
Hibernate: update Employee set FIRST_NAME=?, LAST_NAME=? where ID=?

Hibernate: select employeeen0_.ID as ID1_1_0_, employeeen0_.FIRST_NAME as FIRST_NA2_1_0_, 
employeeen0_.LAST_NAME as LAST_NAM3_1_0_ from Employee employeeen0_ where employeeen0_.ID=?

temp

In above example, we made the ‘emp‘ object persistent using first save() method. Afterward when we updated the last name to ‘temp‘, an update query was executed as expected. This we verified in returned data as well. This is the correct way to work with hibernate persistent entities.

2. Hibernate saveOrUpdate() method

In discussion of save() method, we forgot about case where we had to save persistent entity in another session and that got resulted in duplicate key error. That is also a valid scenario.

To handle such cases, you must use saveOrUpdate() method. Strictly speaking, you should use saveOrUpdate() with even non-persistent entities. Personally, I do not see any harm in doing so. Though, It may make you a little bit careless. So be cautious.

2.1. Hibernate saveOrUpdate() example

Let’s see how saveOrUpdate() method can be used along with entity persisted with save() method.

public class SaveOrUpdateMethodExample
{
   public static void main(String[] args)
   {
      Session sessionOne = HibernateUtil.getSessionFactory().openSession();
      sessionOne.beginTransaction();
      
      //Create new Employee object
      EmployeeEntity emp = new EmployeeEntity();
      emp.setEmployeeId(1);
      emp.setFirstName("Lokesh");
      emp.setLastName("Gupta");
      
      //Save employee
      sessionOne.save(emp);
      sessionOne.getTransaction().commit();
      
      Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
      sessionTwo.beginTransaction();
      
      emp.setLastName("temp");
      //Save employee again second time
      sessionTwo.saveOrUpdate(emp);
      
      sessionTwo.getTransaction().commit();
      HibernateUtil.shutdown();
   }  
}

Program Output.

Hibernate: insert into Employee (FIRST_NAME, LAST_NAME, ID) values (?, ?, ?)
Hibernate: select employeeen_.ID, employeeen_.FIRST_NAME as FIRST_NA2_1_, employeeen_.LAST_NAME as 
		LAST_NAM3_1_ from Employee employeeen_ where employeeen_.ID=?
Hibernate: update Employee set FIRST_NAME=?, LAST_NAME=? where ID=?

Now we are able to save the entity as well as update the entity as well using saveOrUpdate() method.

Please remember that if you have used saveOrUpdate() method in place of save() method above, then also result would have been same. saveOrUpdate() can be used with persistent as well as non-persistent entities both. Persistent entities will get updated, and transient entities will be inserted into database.

3. Suggestion For production code – best practices

It wouldn’t be advisable to try to use above code in production code. Ideally, what you would do is pass VO object to DAO layer, load the entity from the session and update the entity with by copying VO data onto it. This means that the updates take place on a persistent object, and we don’t actually have to call Session.save() or Session.saveOrUpdate() at all.

Once an object is in a persistent state, Hibernate manages updates to the database itself as you change the fields and properties of the object. It’s big relief.

4. Summary

  1. Save() method stores an object into the database. It will Persist the given transient instance, first assigning a generated identifier. It returns the id of the entity created.
  2. SaveOrUpdate() calls either save() or update() on the basis of identifier exists or not. e.g if identifier does not exist, save() will be called or else update() will be called.
  3. Probably you will get very few chances to actually call save() or saveOrUpdate() methods, as hibernate manages all changes done in persistent objects.

Let me know is something is not clear or needs more explanation related to hibernate save() and saveOrUpdate() methods.

Happy Learning !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

19 thoughts on “Hibernate save() and saveOrUpdate() methods”

  1. Dear Sir,

    While submitting the web form entitymanager.merge() is inserting data instead of updating.Why is it happening.

    Regards
    Vinay

    Reply
  2. In Clusterred environment, we have 2 nodes. I have a job which runs on clustered env. Situation is , when this cron job started, using its status whether it is PENDING or InProgress , node will pick that job and start it.
    Node picks up the job on basis of status ie. if Status is PENDING then job will start by respective node. So here to avoid , job to be picked up by both the node, before start the job we, updated the status from Pending to In Progress.

    In current code, we first update Status=IN Progress and start the process but this change doesn’t get committed to DB till whole transaction gets completed and in between that 2nd node picks this job again and starts working on it.

    This situation puts job into deadlock.

    Is there any way in Hibernate Transaction where i can commit status before complete the transaction so other node can understand that this job is already in progress with first node.?

    Reply
    • Hi Deepak, I am not aware of any such technique in hibernate. Though I have faced similar problem in one of projects, but we were using iBatis there so the solution does not apply here.

      Reply
  3.  
    
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
       
    for ( int i=0; i<100000; i++ ) {
        Customer customer = new Customer(.....);
        session.save(customer);
        if ( i % 20 == 0 ) { //20, same as the JDBC batch size
            //flush a batch of inserts and release memory:
            session.flush();
            session.clear();
        }
    }
       
    tx.commit();
    session.close();  
    

    In this example, for every 20 records data will be flushed i.e. data will be persisted in the database, if any record thrown error while processing any record after flush what will happen? as per the transaction concept whole activity i.e. saving 1000000 records should be rollback , but we already saved first 20 records in the database. How Transaction concept will work this scenario? please explain me in understanding session.flush vs tx.commit when we use together .

    Reply
    • Well, you are right in your understanding. Ultimately, it all boils down to fact how you want to handle the error.

      I will put the code inside for-loop in a try-catch block, if any error is received I will try again to run that 20 statements, if succeeded – move ahead to next set of 20; if not then simply log them somewhere and continue processing next set of 20 records.

      Reply
    • Hi Satish,

      You can also used try catch block. As Lokesh suggest. If you want to continue you can do something in catch block( mean get the index number where it stop and start again).

      If you want to stop execution and you want those 20 record should not be in database you can rollback the transaction in catch block.

      Thanks,
      Bhargav

      Reply
  4. 2.SaveOrUpdate() calls either save() or update() on the basis of identifier exists or not. e.g if identifier does not exist, save() will be called or else update() will be called

    I am confused as ID is given when we save so it should not be vice- versa.
    i.e if identifier does not exist, update() will be called or else save() will be called ?

    Reply
  5. I didn’t understand the contents of “Suggestion For Production Code” section. In this section you are telling to pass VO object instead of calling session.save() or session.saveOrUpdate(). What is the meaning of VO object here. we generally use saveOrUpdate() method. What’s wrong in using it explicitly. What’s the benefit of using VO object???

    Reply
    • Probably in your application, VO and entities are same objects. In that case, your argument is valid.
      If both are different objects, then I “suggested” the way. How you guys do it?

      Reply
      • We use AbstractDao layer or baseDao you can say. And we write DAO classes extending this abstract dao class. So all I understand that it removes boiler plate code. And after all we define these generic methods like saveOrupdate(), delete, findById(). So that we don’t have to write these methods in every DAO class. But I don’t know what you mean here using VO object. What is this term VO. Could you please elaborate it.

        Reply
        • VO = View Objects; which you pass to your view layer. These are generally separate than DTO (or entities in this case) objects. You fetch data onto DTO, copy to VO and then return VO to controller. Controller passes VO to view later. Generally happen like this.

          Keeping DTO and VO separate helps in evolving view layer and data layer independently.

          Reply
          • Yes, I think you are telling that sometime DTO objects are exactly as same as entity class and sometime some of the fields of DTO are different from entity class. For example One DTO or VO may contain data from two entity classes and we process it in service layer I mean transfer the values to entity object so that we can save or update in database. I don’t know if I understood the same what you meant or not. But what ever you are telling sounds good. Could you please provide some link or example where I can see this scenario implemented. I mean I can practically understand the benefit of using VO object. Thanks 🙂

          • You got it right. Please note that what I call View Object, is called Domain Object [DO] as well by many others. If you search for “DO vs DTO”, you will find many good links.

            In short, most notifiable difference between them is that DO can have some view related business logic i.e. formatting field or validating it; whereas DTOs contain only setter and getter methods (well mostly).

Leave a Comment

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.