Background

The topic of Fetch types in Hibernate is a fairly advanced topic, as it requires you to have a decent understanding of the Java programming language, as well as have had exposure to SQL and the Hibernate framework for Java. In this post I'm going to assume that you posses this knowledge, if you do not, then I suggest you follow along with my podcasts available here.

What the heck is a Fetch Type?

Great question! Hibernate is a very handy framework for removing your need to fully understand SQL, but it will force you to understand things such as joins.

Joining two tables in SQL is the foundation of a relational database, as joins allow you to actually define relationships between tables (objects).

Having said that, relationships are important to understand when talking about fetch types in Hibernate. This is the case because whenever you define a relationship in Hibernate, you'll also need to define the fetch type. The fetch type essentially decides whether or not to load all of the relationships of a particular object/table as soon as the object/table is initially fetched.

An example of this would be as follows, consider this User object:

public class User
{
  import javax.persistence.OneToOne;
  import javax.persistence.JoinColumn;

  private String username;
  private String password;
  private Profile userProfile;

  // omitting code for getters and setters for username, password

  @OneToOne
  @JoinColumn(name="user_profile_id")
  private Profile getUserProfile()
  {
    return userProfile;
  }

  private void setUserProfile(Profile userProfile)
  {
    this.userProfile = userProfile;
  }
}

Can you spot the relationship in this User object?

If you can't, no worries, there's an easy way to spot it!

Any time you see a @OneToOne, @OneToMany or @ManyToMany annotations, you've got a relationship. What's important to note is that the fetch type should be specified within those annotations, if you don't specify one then it defaults to FetchType.LAZY.

What this means is that when you load up an instance of the User class via a Hibernate query, Hibernate will NOT load this User's Profile unless you explicitly ask it to. So this means that if you try to call user.getUserProfile(), you'll get a NULL.

Difference Between EAGER and LAZY

Okay, so we talked about the fact that FetchType.LAZY is the default fetch type for all Hibernate annotation relationships. We also talked about the fact that when you use the Lazy fetch type, Hibernate won't load the relationships for that particular object instance. So then, what's the difference between Eager and Lazy?

Fetch type Eager is essentially the opposite of Lazy, Eager will by default load ALL of the relationships related to a particular object loaded by Hibernate. This means that if you change the relationship to be this:

  import javax.persistence.FetchType;
  //....
  //....
  //....

  @OneToOne(fetch=FetchType.EAGER)
  @JoinColumn(name="user_profile_id")
  private Profile getUserProfile()
  {
    return userProfile;
  }

Hibernate will now load the user profile into the user object by default. This means that if you access user.getUserProfile() it won't be NULL (unless the joining table actually doesn't contain a matching row by the “user_profile_id” join column).

So, the long story short here is:

FetchType.LAZY = Doesn't load the relationships unless explicitly “asked for” via getter
FetchType.EAGER = Loads ALL relationships

Pros and Cons

If using the lazy loading approach can cause NullPointerExceptions, then why the heck would you want to use it? Well, let's just take a minute to think about this.

Let's assume we had a User object that has 10 different relationships to other objects. Let's also say that you have a user that's trying to login and you just want to check to see if their username and password is correct and matches what's stored in the database. Would you really want to load ALL 10 relationships and NOT make use of ANY of those loaded relationships? Remember, loading things from a database is fairly “expensive” in terms of the time it takes to load all that information into a Java objects AND keep them in memory. And what happens if one of the relationships points to an object that ALSO has 10 relationships (and all of those are set up as fetch type EAGER). Think of the cascading massacre of objects loaded from the database into memory!

The way I like to put it is like this:

    • EAGER: Convenient, but slow
    • LAZY: More coding, but much more efficient

How to Properly use Lazy Loading w/ Spring

So having outlined the differences between these two approaches, I hope you realize that Lazy loading is a suggested route to take your application code in most scenarios. So having said that, how do we make use of Lazy loading with a Spring enabled application?

The important thing to remember is that when using a Spring/Hibernate application, there's a bit of code that is handled for you in the background that you don't actually see. The code that you don't see is the transactional code (enabled by the @Transactional annotation in your DAOs) and this is something that you always need to keep in mind when using Lazy loading.

Having said that, let's take a look at an example of Lazy loading using our User object. Let's assume we have our User object which has a Lazy load fetch enabled to the Profile object. So we will need to design our UserDao with this relationship in mind. One approach is to create two separate getter methods like so:

/**
* This UserDao object is being constructed under the assumption that the relationship
*  to the Profile object is being Lazily loaded using FetchType.LAZY
*/
@Repository
@Transactional
public class UserDao
{
  @Autowired
  private SessionFactory sessionFactory;

  public User getUserById(Long userId)
  {
    Session session = sessionFactory.getCurrentSession();

    // this will invoke the
    return (User) session.createCriteria(User.class).add(Restrictions.idEq(userId)).uniqueResult();
  }

  public User getUserWithProfileById(Long userId)
  {
    Session session = sessionFactory.getCurrentSession();

    User user = (Users) session.createCriteria(User.class).add(Restrictions.idEq(userId)).uniqueResult();
    // this will force SQL to execute the query that will join with the user's profile and populate
    //  the appropriate information into the user object.
    Hibernate.initialize(user.getUserProfile());

    return user;
  }
}

In the code above you see that we have created two getter methods to load the User object from our database via Hibernate.

This means that when you want to load a User object without any relationships (i.e. when you're checking to see if the login information is valid) then you can call getUserById and this will bypass the unnecessary join to the Profile object/table. But if you are in a situation where you DO need to refer to the User‘s profile, then you can call the getUserWithProfileById.

Make sense?

Fun Fact

I was struggling with this Lazy loading concept at first and I'll share the secret as to why. If you are using lazy loading and you were to invoke the getUserById method, you know that it won't load the profile relationship… but what happens if you've inserted a breakpoint into this getUserById method and you CLICK on the user's profile listing in the “Variables” tab inside of Eclipse/STS?

Hibernate will automatically invoke that SQL join and populate the relationship for you!

This was confusing the heck out of me because when I clicked on the profile, it was showing up just fine in the “variables” section, and then my subsequent code was working normally (I wasn't getting NullPointerExceptions) This was so strange and it wasn't until I looked at the console log that I realized as SOON as I clicked on that profile property, hibernate was executing the SQL query and populating the object.

So be wary, it's almost like a quantum physics problem… the act of observing lazy loading changes the outcome of the code flow!

Also, be sure to grab the free Video Tutorial for Eager vs Lazy Loading in Hibernate

And if you'd like more help and guidance in becoming a full stack Java developer, considering joining our Bootcamp, which re-opens again soon.

The Best 7 Java Programming Resources

Alright, so if you're read this far down the article, then you're clearly interested in learning how to code. We actually have a free guide that outlines the best 7 resources for Java programmers.

When you sign up you'll receive the guide immediately and you'll also receive a few emails a week that will help you speed up your Java learning process so you can get up and running as fast as possible.

Go ahead an click the button below to get started!

CAREFUL! Don't Push This Button If You're Not Ready To FINALLY Learn How to Code

Free Java Beginners Course

Start learning how to code today with our free beginners course. Learn more.