Saturday, August 1, 2009

Hibernate get() Vs load()

Hibernate get() Vs load()
1. Load method will not hit the database until any field/property of the instance that we load is accessed i.e
a) User u = (User) session.load(User.class, new Long(1));
b) System.out.println("User is: "+u.getName());

In the above case, the database hit is performed at step (b) where we are actually accessing a property of the user by calling its getName() method

Get method will perform the database hit immediately when it is called. i.e.
a) User u = (User) session.get(User.class, new Long(1));
b) System.out.println("User is: "+u.getName());

In above case, the database hit is performed at step (a) itself.

2. With load, We cannot access the properties of a JavaBean instance after the session is closed. i.e. the scope of the instance obtained from the load is limited to a session context in which it is called. i.e.
a) User u = (User) session.load(User.class, new Long(1));
b) System.out.println("User is: "+u.getName());
c) session.close();
d) System.out.println("User is: "+u.getName());

In above case, the step 'b' would work fine since we are accessing the user instance in the scope of the session. However, the step 'd' would raise 'LazyInitializationException' because the session is closed
Get method Instances will be active even when the session is closed. i.e.
a) User u = (User) session.get(User.class, new Long(1));
b) System.out.println("User is: "+u.getName());
c) session.close();
d) System.out.println("User is: "+u.getName());

In above case, both steps 'b' and 'd' would work fine

3. Load method will throw an ObjectNotFoundException if the instance that we are trying to load does not exist in the database with the primary key value that we supply.i.e.
a) User u = (User) session.load(User.class, new Long(1));
b) System.out.println("User is: "+u.getName());

In above case, when the load is called and when the database hit is performed at step 'b', if the user with id 1 is not existing in the database, we get 'ObjectNotFoundException' at step 'b' since it hits the database at step 'b'
Get method will return null if the instance with the id we specify is not found, so we can check for null values

Small gottcha with session.load():
One Very important we must note is that when we give the following kind of statement:
User u = (User) session.load(User.class, new Long(15));
Then if we just pass that instance variable 'u' as it is to some other Class (like address.setUser(u)) without accessing any of u's property (like u.getName(), but NOT u.getId()), or if we just call u.getId() there itself, we wont get any exception and u.getId() will print whatever id we have passed for loading the user (15 in this case) even if that row doesnot exist in the database.
The reason is, in the load method, the second parameter passed will be considered and set as the id parameter by default for whatever is being loaded and after some other property is accessed like getName() etc, it will be overriden (which again would be same value if the user with that id exist in the database otherwise an exception will be thrown at that point).
To clarify the above point, consider the following example:
class User {
private int id;
private String name;
public User(int id,String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String Name() {
return name;
}

public String toString() {
return "User id = "+this.getId();
}
}


Now, Consider another class like Address as:

class Address {
private int id;
private User user;

public Address(int id, User user) {
this.id = id;
this.user = user;
}
}


Now, let us say that currently there is no user in the database.
Then,
User user = (User) session.load(User.class, new Integer(1));
System.out.println("User id = "+user.getId());
Address address = new Address(1,user);
session.save(address);

The first 3 lines from above code works just fine and we wont get any exception (even though no users are there in database). Here,
second line will give the output as: User id = 1
third line will consider the dummy user itself.
However, when we try to save the address which has a user associated with it through a foreign key relation and since we did not find any user, the batch update that is being performed for saving address along with its user fails and we get Could not execute JDBC Batch update exception.

However, if change the above example as follows:

User user = (User) session.load(User.class, new Integer(1));
System.out.println(user); (or) System.out.println(user.getName());

Then, the actual database hit is performed and we get the exception we wanted. This is because, we are performing the toString method on user in first case (Which is overriden and now returning the actual id of the user through its this.getId). Even if we dont override the toString() method, and try to log the user on console as System.out.println(user), ObjectNotFoundException would be thrown . And in second case, we are accessing a property other than id i.e. getName() is called on u, so the database is hit and it will NOW try to get the user details with that id which could not be found.

This can be a considered as a bit of a gottcha in load method of session since it is mentioned that load() will perform the hit as soon as any of the property of that particular instance which is being loaded is accessed and if it is not found, we get ObjectNotFoundException immediately. However, the 2 cases in which we consider we do not get the ObjectNotFoundException is:
1. We access the id property
2. We pass the loaded instance to another instance without accessing any of loaded instance's properties.

No comments:

Post a Comment