0

I was bit confused with save, saveOrUpdate and merge. Below is the test I used to check and got even more confused now :).

DESC: I have Emp and Certs entities. The Emp and Certs have a parent child relationship mapped using One-to-Many. I make a call to saveEmployee() method from Main method and call save(), saveOrUpdate() and merge() methods one by one to test their behaviors

Emp Entity

@Entity
@Table(name = "tmp_emp")
public class Emp {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "EMP_ID")
private Long empId; 

@Column(name = "FIRST_NAME")
String firstName;

@Column(name = "LAST_NAME")
String lastName;

@Column(name= "SALARY")
Integer salary;

@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "emp")
Set<Certs> certSet;

//  getters-setters

Certs Entity

@Entity
@Table(name = "tmp_certs")
public class Certs {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "EMPCERT_ID")
private Long empCertId; 

@Column(name = "CERT_NAME")
String certName;

@ManyToOne(targetEntity = Emp.class)
@JoinColumn(name = "EMP_ID")
private Emp emp;

//getters-setters

Main method

public static void main(String[] args) {
    AnnotationConfiguration config = new AnnotationConfiguration();     
    config.configure("hibernate-config.xml").addAnnotatedClass(Emp.class);
    config.configure("hibernate-config.xml").addAnnotatedClass(Certs.class);
    SessionFactory factory = config.buildSessionFactory();

// Creating 1st Cert object, set cert name
    Certs cert1 = new Certs();
    cert1.setCertName("OCJP");

// Creating 2nd Cert object, set cert name
    Certs cert2 = new Certs();
    cert2.setCertName("PMP");

// Creating a Hashset to store Certs
    Set<Certs> certsSet = new HashSet<Certs>();

// Adding certs to Hashset
    certsSet.add(cert1);
    certsSet.add(cert2);

// Creation of Emp Object.
    Emp emp = new Emp();

// First call to saveEmployee method.
    saveEmployee(emp, "Rick", "Ved", 3000, factory, certsSet);

// Second call to saveEmployee method with same emp and certs hashset.
    saveEmployee(emp, "George", "Tank", 5000, factory, certsSet);

}

Below is the saveEmployee method. I have used saveOrUpdate(), save() and merge() methods one by one.

private static void saveEmployee(Emp emp,String fname,String lname,Integer sal, SessionFactory factory, Set<Certs> certsSet) {      
    Session session = factory.openSession();
    Transaction tx =null;
    try{
        tx = session.beginTransaction();

// Setting Firstname, Lastname and Salary of emp object.            
        emp.setFirstName(fname);
        emp.setLastName(lname);
        emp.setSalary(sal);

// Iterate Cert Hashset and set empId to Cert Objects.
        Iterator<Certs> itr = certsSet.iterator();
        while(itr.hasNext()){               
            Certs c = itr.next(); c.setEmp(emp);
        }
        emp.setCertSet(certsSet);
        session.saveOrUpdate(emp);  // CASE 1
//      session.save(emp); // CASE 2
//      session.merge(emp);  //CASE 3
        session.flush();
        tx.commit();
    }catch(HibernateException e){
        if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      }finally {
// Close the session.
         session.close(); 
      }
}

Case 1: saveOrUpdate()

Methods save() and merge() commented. Results are as below:

tmp_emp table:

enter image description here

tmp_certs table

enter image description here

So from this and hibernate sqls I can infer that the Emp entity and Certs got inserted first and later all 3 got updated. I suppose its fine with an initial insert and later an update.

Case 2: save()

Methods saveOrUpdate() and merge() commented. Results are as below:

tmp_emp table

enter image description here

tmp_certs table

enter image description here

Here it's a call to save method. Again same Emp and Certs objects for both sessions. This time emp object was considered as 2 objects and both employees got saved to emp table. But again Certs were treated as same objects. They got inserted and later got updated(with new empId). Hibernate SQL too shows the same. 2 Inserts for Emp, 2 Inserts for Certs then 2 update on same Certs ( can see empId: 112 updated on certs)

Case 3: merge()

Methods save() and saveOrUpdate() commented.Results are as below

tmp_emp table

enter image description here

tmp_certs table

enter image description here

Here using merge() each time Emp as well as Certs objects are getting treated as new objects. So there are 2 Inserts for Emp and 4 Inserts for Certs in Hibernate sql.

I went through this LINK but am not able to relate to these cases. Any help in understanding this behavior would be greatly appreciated.

Community
  • 1
  • 1
pranav
  • 421
  • 1
  • 11
  • 27

1 Answers1

0

I have not read you question, it is a little confusing as to what you are trying to do. But, i'll explain it here.

  1. session.save() on transient/detached object will always create a row in the database table.
  2. session.saveOrUpdate() will save a transient object or update a detached object. If there is a persistance object present in the session already then it will throw an exception saying that an object with that id is already in the session.

eg:

public void saveSomething(Something one){//here one.id = 33 too
    ..
    Something second = (Something) session.get(Something.class, 33); //get entity of id 33

    //try to update one here
    session.saveOrUpdate(one); 

    //commit your transaction...  EXCEPTION WILL BE THROWN AS SOMETHING OBJECT WITH 33 ID IS IN THE SESSION ALREADY
}
  1. session.merge() will replace the value in the session with that of the detached object. it does not care what you do with the actual entity which is in the session. No exceptions will be thrown.

eg:

public void saveSomething(Something one){
    //here one.id = 33 too
    //one.name ='Abdulla'

    ..
    Something second = (Something) session.get(Something.class, 33); //get entity of id 33. 
    //second.name = 'Frank'
    //second.age = 33
    //change name here to Mark
    second.setName('Mark');
    //try to merge one here into the session.
    session.merge(one);     
    //now the session will have values of 'one' in it as they are replaced
    Something third = (Something) session.get(Something.class, 33);
    //now you'll get the following values if you try to get the 
    //value as you have overwritten what is already present in the session. 
    //You'll not get Mark as they are replaced by the merge operation.
    //third.id = 33
    //third.age = 33    
    //third.name ='Abdulla' 
}
Zeus
  • 6,386
  • 6
  • 54
  • 89
  • Zeus, Actually I have a emp entity and 2 certs entities. The emp and certs have a parent child relationship mapped using One-to-Many. I make a call to **saveEmployee** method from **main** method and call **save**, **saveOrUpdate** and **merge** methods to test their behaviors. After 1st call to saveEmployee objects acts as detached for 2nd call. **saveOrUpdate()** as per your explanation is very correct. But **save()** has inserted records in emp, updated for certs. **merge()** is the one which have made inserts for both calls to saveEmployee. Please let me know if am not clear enough. – pranav Mar 12 '15 at 14:09
  • Can someone please explain what's exactly happening? I tried best to explain the scenarios, please inform if am not clear with my question. – pranav Mar 24 '15 at 04:27
  • Hey..i was not following stack overflow for some time. Best way to gain attention is to edit your question. Add more details. – Zeus Mar 24 '15 at 04:29