Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate: Details of Proxy Implementation (Lazy Fetching)

I've learned that Hibernate does not return an instance of your actual entity class when it gives you the result of a query, but instead returns a 'proxy' instance that is dynamically sub-classed from your actual entity's class. I understand the reason for this behaviour, being that it allows for the realization of the lazy initialization. However, I have a few questions left unanswered on the details of the implementation of these proxy classes:

  1. Will the lazy fetched field get loaded ONLY when I use the getter? What if I use the field in, say, my equals or hashCode method? Will the execution of these methods result in a NullPointerException when I have not called the getter of this field before?

  2. How exactly does Hibernate initialize the field when its initialization is triggered? Does it execute the field's setter method that I have defined in the entity class, or will it assign the value directly to the variable, via reflection or something like that?

like image 959
user3237736 Avatar asked Sep 18 '15 20:09

user3237736


People also ask

What is proxy in Hibernate lazy loading?

By definition, a proxy is “a function authorized to act as the deputy or substitute for another”. This applies to Hibernate when we call Session. load() to create what is called an uninitialized proxy of our desired entity class. Simply put, Hibernate subclasses our entity class, using the CGLib library.

How can we get lazy loading in Hibernate?

To enable lazy loading explicitly you must use “fetch = FetchType. LAZY” on an association that you want to lazy load when you are using hibernate annotations. @OneToMany( mappedBy = "category", fetch = FetchType.

What is proxy pattern in Hibernate?

How hibernate uses proxy pattern: Hibernate uses proxy pattern to lazy load entities. For lazy loaded entity or collection, hibernate defers database hit till any property other than identifier (Property marked with @Id) is accessed. The proxy object which hibernate creates has only identifier value set.

What is eager fetch and lazy loading in Hibernate?

In eager loading strategy, if we load the User data, it will also load up all orders associated with it and will store it in a memory. But when we enable lazy loading, if we pull up a UserLazy, OrderDetail data won't be initialized and loaded into a memory until we make an explicit call to it.


Video Answer


1 Answers

First, two rules:

  1. Proxies delegate all non-final method calls to the target instance, except the method for getting id if property access for id is defined in the mappings.
  2. Proxy object instances are never initialized, the target instance is initialized.

1) Suppose that you invoke a.equals(b) where both a and b are proxies of the same entity. And lets say that equals method is implemented like this:

public boolean equals(Object other) {
  ...
  if (this.someField.equals(other.someField)) {
    ...
  }
  ...
}

The equals method of a is delegated to the target instance forcing its full initialization. So you are safe regarding the fields in the a instance (you can use them directly).

However, accessing the fields directly in the b instance (other.someField) is never valid. It does not matter whether b is initialized or not, proxy instance is never initialized, only the target instance. So, someField is always null in the b instance.

The correct implementation is to use getters at least for other instance:

this.someField.equals(other.getSomeField())

or to be consistent:

this.getSomeField().equals(other.getSomeField())

Things are different when it comes to final methods - Hibernate can't override them to delegate the call to the target. So, if the equals method were final in the previous example, you would get a NullPointerException when accessing this.someField.

All of this can be avoided by configuring Hibernate to use bytecode instrumentation instead of proxies, but that has its own pitfalls and is not adopted widely.

2) Again, it never initializes the proxy instance itself. When it comes to the target instance initialization, it depends whether field or property access is defined in the mappings. In both cases reflection is used (to assign values directly to fields in case of field access or to invoke setters in case of property access).

like image 74
Dragan Bozanovic Avatar answered Oct 20 '22 09:10

Dragan Bozanovic