Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate ignores fetchgraph

This is my entity:

public class PersonItem implements Serializable{
    @Id
    @Column(name="col1")
    private String guid;

    @Column(name="col2")
    private String name;

    @Column(name="col3")
    private String surname;

    @Column(name="col4")
    private Date birthDate;
 //+getters and setters
}

This is how I get the list of persons:

Query query = em.createQuery("Select p from PersonItem p WHERE p.guid IN (:guids)");
EntityGraph<PersonItem> eg = em.createEntityGraph(PersonItem.class);
eg.addAttributeNodes("guid");
eg.addAttributeNodes("name");
eg.addAttributeNodes("surname");
query.setHint("javax.persistence.fetchgraph", eg);
query.setParameter("guids", guids);
List<PersonItem> list=query.getResultList();
em.close();
// And now I iterate result AFTER EM CLOSE
....iterate

If I understand fetch graph correcly it must load only those fields, which I specified. However, the field "birthDate" is also loaded. Besides I see that in hibernate sql query 4 columns are selected.

How to fix it? I use hibernate 5.1.0 as JPA provider.

like image 836
Pavel_K Avatar asked May 05 '16 15:05

Pavel_K


1 Answers

Entity graphs are meant to control which relationships (e.g. one-to-one, one-to-many, etc.) are loaded lazily or eagerly. They may not work for loading individual columns (it depends on the provider).

Hibernate has some support for this, but it is fairly difficult to get working, described here. However, they mention the following reticence towards this approach (which I whole-heartedly agree with):

Please note that this is mostly a marketing feature; optimizing row reads is much more important than optimization of column reads.

So I would not recommend going too far down this road until you've confirmed that this is indeed a bottleneck in your application (e.g. this kind of fetch tuning can be a symptom of premature optimization).

UPDATE:

As pointed out, JPA does leave it up to the provider as to whether or not simple columns (non-associations) are lazily fetched.

The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed. The implementation is permitted to eagerly fetch data for which the LAZY strategy hint has been specified. In particular, lazy fetching might only be available for Basic mappings for which property-based access is used.

Starting with Hibernate 5, official support for bytecode enhancement was added and this may allow for lazy attribute fetching.

From the latest Hibernate docs we have:

2.3.2

fetch - FetchType (defaults to EAGER)

Defines whether this attribute should be fetched eagerly or lazily. JPA says that EAGER is a requirement to the provider (Hibernate) that the value should be fetched when the owner is fetched, while LAZY is merely a hint that the value be fetched when the attribute is accessed. Hibernate ignores this setting for basic types unless you are using bytecode enhancement.

And this next snippet that describes the advantages of bytecode enhancement.

Lazy attribute loading

Think of this as partial loading support. Essentially you can tell Hibernate that only part(s) of an entity should be loaded upon fetching from the database and when the other part(s) should be loaded as well. Note that this is very much different from proxy-based idea of lazy loading which is entity-centric where the entity’s state is loaded at once as needed. With bytecode enhancement, individual attributes or groups of attributes are loaded as needed.

like image 191
Pace Avatar answered Nov 18 '22 03:11

Pace