Hibernate allows detached objects to be associated with a persistence context again.One way to achieve this is to use the update method of the session.
In this case, even if no changes are made to the object the SQL query will be fired. In such a scenario when the detached object is not modified we can use the lock() method to make it persistent again.
This can be verified by the below code. The detached instance was modified and then associated with a second session using lock.
Unless the object gets modified (while in persistent state) or an explicit update call is made, Hibernate will not schedule it for an update query.
There is also a third technique - session.merge() which is capable of making a detached object persistent again.
public static void reattachUsingUpdate() { Session session1 = sessionFactory.openSession(); Entity entity = (Entity) session1.get(Entity.class, 1); //The object is now persistent session1.close(); //The object is now detached //no dirty marking on it currently entity.setData("Modifying the value outside session"); Session session2 = sessionFactory.openSession(); Transaction transaction = session2.beginTransaction(); session2.update(entity); //The object is now persistent again transaction.commit(); session2.close(); }The update method forces an update operation to be fired for the passed object. As this object is detached, Hibernate adds this object to the persistence context (making it persistent) and treats it as dirty. Hibernate now schedules an SQL Update query which is fired when the session is flushed - either on transaction commit/before execution of a (related) query or on explicit call to session.flush().
In this case, even if no changes are made to the object the SQL query will be fired. In such a scenario when the detached object is not modified we can use the lock() method to make it persistent again.
public static void reattachUsingLock() { Session session1 = sessionFactory.openSession(); Entity entity = (Entity) session1.load(Entity.class, 1); //The object is now persistent session1.close(); //The object is now detached //changes made at this point has no impact Session session2 = sessionFactory.openSession(); Transaction transaction = session2.beginTransaction(); session2.lock(entity, LockMode.NONE); //The object is now persistent again System.out.println("data is " + entity.getData()); transaction.commit(); session2.close(); }When the lock method is called, the detached object is added to the persistence context. However no dirty check happens. So if the object was modified when it was in the detached state, Hibernate is not aware of it.
This can be verified by the below code. The detached instance was modified and then associated with a second session using lock.
public static void reattachUsingLock() { Session session1 = sessionFactory.openSession(); Entity entity = (Entity) session1.get(Entity.class, 1); session1.close(); //The object is now detached //changes made at this point has no impact entity.setData("Changed Data"); Session session2 = sessionFactory.openSession(); Transaction transaction = session2.beginTransaction(); session2.lock(entity, LockMode.NONE); //The object is now persistent again transaction.commit(); session2.close(); }This object will not be updated. The reason being when u add an object with lock, the session assumes that this object is in the same state as an object loaded from the database. Hence unless you make some changes to the now persistent object, no update queries will be fired. Now consider this code:
public static void reattachUsingLockandSave() { Session session1 = sessionFactory.openSession(); Entity entity = (Entity) session1.load(Entity.class, 1); System.out.println(entity.getData()); //The object is now persistent session1.close(); //The object is now detached //changes made at this point has no impact String originalData = entity.getData(); entity.setData("Changed Data"); Session session2 = sessionFactory.openSession(); Transaction transaction = session2.beginTransaction(); session2.lock(entity, LockMode.NONE); entity.setData(originalData); //The object is now persistent again and also dirty transaction.commit(); session2.close(); }I have called a setter to the reattached object (in reality I have only restored the objects original value - making it an exact copy of the db record). But calling the setter tells Hibernate that a persistent object changed and it will schedule it for an update.
Unless the object gets modified (while in persistent state) or an explicit update call is made, Hibernate will not schedule it for an update query.
There is also a third technique - session.merge() which is capable of making a detached object persistent again.
Nicely explained. Thank you
ReplyDelete