ChatGPT解决这个技术问题 Extra ChatGPT

Hibernate: Difference between session.get and session.load

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!!


N
Nandkumar Tekale

From the Hibernate forum:

This from the book Hibernate in Action. Good one read this..

Retrieving objects by identifier The following Hibernate code snippet retrieves a User object from the database:

User user = (User) session.get(User.class, userID);

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:

User user = (User) session.load(User.class, userID);

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.


I am debugging an issue right now where session.Get() is returning a proxy!
Thanks a lot! The money part for me was: "If load() can’t find the object in the cache or database, an exception is thrown. The get() method returns null if the object can’t be found."
The JavaDoc for Session.get says: 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, or a proxy for the instance, is already associated with the session, return that instance or proxy.) So the section from book that says: "On the other hand, get() never returns a proxy." is not correct.
if you are using a transaction management strategy with your daos, you may prefer get(). otherwise the caller will need to also be executing in the context of an open hibernate session in case load() returns a proxy. for example, if you are doing MVC, your controller may execute dao.load() and then throw an exception when trying to access the proxy object later if there is no valid session. doing dao.get() will return the actual object to the controller regardless of the session (assuming it exists)
The issue that @Vicky described can cause headaches, and I don't see any advantage of it. In some cases I additionally need the identifier for further parametrized queries. But since a proxy of the object is already in the session, the getter of the identifier returns null. Why do they retrieve the proxy instead the real instance if that proxy is in the session?
J
Jorge Alves

Well, in nhibernate at least, session.Get(id) will load the object from the database, while session.Load(id) only creates a proxy object to it without leaving your server. Works just like every other lazy-loaded property in your POCOs (or POJOs :). You can then use this proxy as a reference to the object itself to create relationships, etc.

Think of it like having an object that only keeps the Id and that will load the rest if you ever need it. If you're just passing it around to create relationships (like FKs), the id is all you'll ever need.


so you want to say load(id) will first hit the database to check either it is valid id or not and than will return the proxy object and when the properties of this object are accessed it hits the database again? isnt it an unlikely scenario? two queries to load single object?
No, load(id) will not validate the id at all so no round-trips to the DB. Use it only when you are sure you're sure it's valid.
V
Vishal Sharma

session.load() will always return a “proxy” (Hibernate term) without hitting the database. In Hibernate, proxy is an object with the given identifier value, its properties are not initialized yet, it just look like a temporary fake object. If no row found , it will throws an ObjectNotFoundException.

session.get() always hit the database and return the real object, an object that represent the database row, not proxy. If no row found , it return null.

Performance with these methods also makes diff . between two...


Same wording as on mkyong.com/hibernate/… (But I don't know who was first)
m
madhu_karnati

One more Extra point::

get method of Hibernate Session class returns null if object is not found in cache as well as on database. while load() method throws ObjectNotFoundException if object is not found on cache as well as on database but never return null.


S
SteveT

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.

Session 1                  Session 2
---------                  ---------
Load object
Wait a while..   
                           Load object
                           Modify object property
                           [triggers db 'select' -
                            version read as 10]
                           Commit
                           [triggers db update,
                            version modified to 11]
Modify object property
  [triggers db 'select' -
  version read as 11]
Commit
  [triggers db update,
  version modified to 12]

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.


S
Sanjay

Also we have to be careful while using load as it will throw an exception if the object is not present. We have to use it only when we are sure that object exists.


b
black jack

An excellent explanation is found at http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load() :
It will always return a “proxy” (Hibernate term) without hitting the database.
In Hibernate, proxy is an object with the given identifier value, its properties are not initialized yet, it just look like a temporary fake object.
It will always return a proxy object with the given identity value, even the identity value is not exists in database. However, when you try to initialize a proxy by retrieve it’s properties from database, it will hit the database with select statement. If no row is found, a ObjectNotFoundException will throw.
session.get() :
It always hit the database(if not found in cache) and return the real object, an object that represent the database row, not proxy.
If no row found , it return null.


Y
Yasser Shaikh

load() can’t find the object from cache or database, an exception is thrown and the load() method never returns null.

get() method returns null if the object can’t be found. The load() method may return a proxy instead of a real persistent instance get() never returns a proxy.