10

I am testing hibernate and giving this query to

transaction = session.beginTransaction();
city = new City("A");
city  = (City)session.merge(city);
city.setName("B");
transaction.commit();

And I am getting those queries in the command line:

Hibernate: insert into CITY (name) values (?)
Hibernate: update CITY set name=? where CITY_ID=?

I am using merge not save, so why hibernate is updating my object, It should not update. am it right? What is the mistake?

Elbek
  • 3,434
  • 6
  • 37
  • 49
  • 1
    This link may be useful : http://stackoverflow.com/questions/161224/what-are-the-differences-between-the-different-saving-methods-in-hibernate – Gaurav Jan 13 '12 at 05:04

3 Answers3

23

I will try to explain using a more concrete example. Suppose you have a scenario like below :

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
User userA = (User)session.get(User.class, 1101);
transaction.commit();
session.close();
// Since session is closed, userA is detached.

session = sessionFactory.openSession();
transaction = session.beginTransaction();
User userB = (User)session.get(User.class, 1101);
//Now here,  userB represents the same persistent row as userA.
//When an attempt to reattach userA occurs, an exception is thrown
session.update(userA);
transaction.commit();
session.close();

Exception when an attempt to reattach a Detached object, userA is made.

Exception in thread "main" org.hibernate.NonUniqueObjectException: a   
different object with the same identifier value was already associated
with the session:

This is because Hibernate is enforcing that only a single instance of a Persistent    object exists in memory.

To get around the above problem, merge() is used, as shown below :

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
User userA = (User)session.get(User.class, 1101);
transaction.commit();
session.close();
//userA is now detached as session is closed.

session = sessionFactory.openSession();
transaction = session.beginTransaction();
User userB = (User)session.get(User.class, 1101);
User userC = (User)session.merge(userA);
if (userB == userC) {
  System.out.println("Reattched user is equal");
}
transaction.commit();
session.close();
Gaurav
  • 1,549
  • 2
  • 15
  • 31
4

It's a sequencing issue. Actually not an issue. Hibernate is doing exactly what you told it to do. As @TejasArjun says, merge is about merging in deteched data. here's what is going on:

...
city  = (City)session.merge(city); 
// No different to save(). Hibernate schedules an insert to the
// database to store the current record.

city.setName("B"); 
// The object is now flagged as dirty and needing to be saved. 
// Hiberate automatically tracks properties on objects and knows when they change.

transaction.commit(); 
// Hibernate sees that 'city' has been changed since it was saved, 
// so it schedules an update to store the new data.
drekka
  • 20,957
  • 14
  • 79
  • 135
  • I got your point thanks for answer but even i can reach the above by this way: city.setName("q"); session = HibernateUtil.getSessionFactory().openSession(); transaction = session.beginTransaction(); session.update(city); transaction.commit(); Why then need merge() method? It is the same – Elbek Jan 13 '12 at 05:21
  • See my example on usage of merge in second answer – Gaurav Jan 13 '12 at 05:26
0

Because session is not closed yet and in persistence terms city object is still attached to session. So, any changes in that object will be listened by hibernate session and appropriate dml statement will be invoked.

Gaurav
  • 1,549
  • 2
  • 15
  • 31
  • that is right if i use save() not merge(). If it is still right for merge then what is the difference between save and merge? – Elbek Jan 13 '12 at 04:51
  • 1
    Merge is useful when you have detached instances. In the above case, when you close the session you still have `city` object. Suppose, you make some changes to `city` object after closing the session. Now again you open a session and you want to make sure the changes are persisted. In this case you would use `merge` the city object with the session and hibernate will make sure the changes are reflected in database. `save` is primarily used to persist an entity and would give back the identifier. – Gaurav Jan 13 '12 at 04:55
  • in this case which u described even i can use update() to update it. no need to use merge() :( – Elbek Jan 13 '12 at 05:05