14

I am trying to understand what the difference is in returned object and behavior of Hibernate 3.6 session.get() and session.load().

From the javadoc:

get():

Return the persistent instance of the given entity class with the given identifier, or null if there is no such persistent instance. (If the instance is already associated with the session, return that instance. This method never returns an uninitialized instance.)

load():

Return the persistent instance of the given entity class with the given identifier, assuming that the instance exists. This method might return a proxied instance that is initialized on-demand, when a non-identifier method is accessed.

I have three questions:

  1. The javadoc does not say when load() might return a proxy - is there any way to know it in advance?

  2. When load() returns a proxy - this means load() did not access the database, am I correct? Then what if I provided load() with an identifier that does not exist in the database? I will now have in the session a proxy with an invalid ID (without getting an Exception). Now I want to let another persistent instance point to that proxy - is it going to work? For this scenario I do not need to initialize the proxy, I only need its id (which I have even though its invalid since it's not in the database). So I guess I am asking if my description is correct, and do I always need to check out after load() the returned object with isInitialized() in order to make sure it represents a valid entity (or at least a valid proxy), i.e. with a valid ID.

  3. Also, what happens if load() returns a proxy - so the proxy is the instance that is already associated with the session. Then according to the description of get(): "If the instance is already associated with the session, return that instance." - so does get() return the proxy? Since according to the description of get(): "This method never returns an uninitialized instance."

Thanks!

UPDATE

Are the following correct?

(A) I think both load() and get() will first try to check the session cache before going to the DB - so it would not be right to say that any of them always hits the DB, or always returns a proxy.

(B) An initialized proxy is not the same as the original instance, as you can read here: http://blog.xebia.com/2008/03/08/advanced-hibernate-proxy-pitfalls/

rapt
  • 11,810
  • 35
  • 103
  • 145

1 Answers1

23

(1) , (3) :

Yes. You are right .Both the load() and get() will first check if there is an instance with the same PK is persisted in the session.

If yes , just returns that instance from the session. (It may be the proxy or the actual entity class instance)

If no , load() will create and return a proxy while get() will hit DB and returns instance of the actual entity class .

The returned object from both methods will be associated and persisted in the session afterwards.

So , whether get() or load() return proxy or the actual entity class depends on whether you use get() or load() to get the instance of the same PK in the current session for the first time.

You can proof this behaviour by performing the following test:

Session session = HibernateUtil.getSessionFactory().openSession();

Item loadItem= (Item ) session.load(Item.class, 1);
System.out.println(loadItem.getClass().getName());

Item getItem = (Item ) session.get(Item .class, 1);
System.out.println(getItem .getClass().getName());

If it is an proxy , the printed class name will not be the same as the actual entity class name. Just change the execution order of to load() and get() to see the effect.

(2):

If load() returns a proxy , it will not access the DB during load() .The proxy will only accesses the DB if their mapped properties besides the PK are accessed and there are no instances with the same PK value is associated with the session.

After the proxy accesses the DB , the instance with the same PK of the proxy will be associated with that session .So when you get another properties from the proxy again or you use get() to get the instance for the same PK , the DB will not be accessed as the values can be found from the session.

For example:

/**Session starts***/
Item item = (Item) session.load(Item.class, new Long(1));
item.getId();  //Will not access DB as only the identifier property is access
item.getDescription(); // access the DB and initialize the proxy . After that , the item proxy is said to be initialized
item.getPrice(); //will not access DB as the item with the PK 1 can be get from the session
Item item2 = session.get(Item.class, new Long(1)) //will not access DB as the item with the PK 1 can be get from the session

If you load() an instance with the invalid ID and then access the properties or call a method (such as isInitialized()) on this proxy , ObjectNotFoundException will be thrown. So if you can catch ObjectNotFoundException , it means a proxy is loaded with an invalid ID.

If you want to ensure the ID is valid during the runtime , you should use get() and check if the returned instance is null . load() is useful when setting the foreign key constraint. See this

Community
  • 1
  • 1
Ken Chan
  • 84,777
  • 26
  • 143
  • 172
  • 1. But if I already had an initialized instance (for this ID) on the session, wouldn't it return that instance, and not a proxy? Also, the javadoc says: "This method might return a proxied instance" - it doesn't say "this method will always". 2. It's kind of design flaw - since according to what you say when I have a proxy and I want to make sure it represents an actual ID in DB (and I always want to make it sure - even if I only use the proxy to point other instances to it) - then I cannot know the ID I used is valid until I initialize it, but in this case, why using a proxy? – rapt Nov 08 '11 at 09:52
  • 3. Do you mean a `get()` after `load()` will return an initialized proxy, or just an initialized instance? Since if it's the later, then we now have in the session two objects that hold the same ID (the proxy and the instance). BTW I know it's possible to have two proxies that represents the same DB ID - as you can read here: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/ under the text "Secondly, it is possible to break proxy". -- See more in UPDATE in my original question. – rapt Nov 08 '11 at 09:54
  • Yes . You are right .Your questions help me to clear some misunderstanding about `get()` and `load()` .See my update please – Ken Chan Nov 08 '11 at 11:06
  • Thank you for the explanation. One thing is missing in this picture though: it says here http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/ObjectNotFoundException.html as follows: "Thrown when Session.load() fails to select a row with the given primary key (identifier value). This exception might not be thrown when load() is called, even if there was no row on the database, because load() returns a proxy if possible." – rapt Nov 08 '11 at 23:54
  • 1
    However according to what you said `load()` will **NEVER** throw this exception: if the instance/proxy is in the session cache it will return it, otherwise it will create a proxy (regardless if ID is in DB) - it would be right to say that a proxy which is returned by `load()` might throw this exception (at some point after `load()` has already returned) - is my understanding correct? If so, the javadoc about this mechanism is misleading, or quite frankly, wrong. – rapt Nov 08 '11 at 23:54
  • From my testing , when I `load()` an item with the invalid ID using `session.load(Item.class, someInvalidId);` , there are no `ObjectNotFoundException` thrown at this line The `ObjectNotFoundException` will be thrown when I access the properties (besides the PK property) of the returned proxy . – Ken Chan Nov 09 '11 at 02:21
  • Note that the docs for `session.load` clearly state: "You should not use this method to determine if an instance exists (use get() instead). Use this only to retrieve an instance that you assume exists, where non-existence would be an actual error." https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Session.html#load(java.lang.Class,%20java.io.Serializable) – Nux May 21 '20 at 15:29