From the API, I could see it has something to do with proxy. But I couldn't find a lot of information on proxy and do not understand the difference between calling session.get
and session.load
. Could someone please explain or direct me to a reference page?
Thank you!!
From the Hibernate forum:
Retrieving objects by identifier The following Hibernate code snippet retrieves a User object from the database:
The get() method is special because the identifier uniquely identifies a single instance of a class. Hence it’s common for applications to use the identifier as a convenient handle to a persistent object. Retrieval by identifier can use the cache when retrieving an object, avoiding a database hit if the object is already cached. Hibernate also provides a load() method:
The load() method is older; get() was added to Hibernate’s API due to user request. The difference is trivial:
If load() can’t find the object in the cache or database, an exception is thrown. The load() method never returns null. The get() method returns null if the object can’t be found.
The load() method may return a proxy instead of a real persistent instance. A proxy is a placeholder that triggers the loading of the real object when it’s accessed for the first time; On the other hand, get() never returns a proxy. Choosing between get() and load() is easy: If you’re certain the persistent object exists, and nonexistence would be considered exceptional, load() is a good option. If you aren’t certain there is a persistent instance with the given identifier, use get() and test the return value to see if it’s null. Using load() has a further implication: The application may retrieve a valid reference (a proxy) to a persistent instance without hitting the database to retrieve its persistent state. So load() might not throw an exception when it doesn’t find the persistent object in the cache or database; the exception would be thrown later, when the proxy is accessed. Of course, retrieving an object by identifier isn’t as flexible as using arbitrary queries.
One indirect consequence of using "load" instead of "get" is that optimistic locking using a version attribute may not work as you'd expect. If a load simply creates a proxy and does not read from the database, the version property is not loaded. The version will only be loaded when/if you later refer to a property on the object, triggering a select. In the meantime, another session can update the object, and your session will not have the original version that it needs to do the optimistic lock check - so your session's update will overwrite the other session's update with no warning.
Here's an attempt to sketch out this scenario with two sessions working with an object with the same identifier. Initial version for object in DB is 10.
We actually want session 1's commit to fail with an optimistic lock exception, but it will succeed here.
Using "get" instead of "load" works around the problem, because get will immediately issue a select, and the version numbers will be loaded at the correct times for the optimistic lock checking.