2

I know that similar questions have already been asked for plenty of times but I haven't found one that could help me.

So, could I ask you to help me to find the cause of why a Book's title is fetched EAGERly?

I have a very simple codebase, here is my entity:

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class Book {

    @Id
    @GeneratedValue
    private int id;

    @Lob
    @Basic(fetch = FetchType.LAZY, optional = false)
    private String title;

}

And here is a client piece of code, in this case represented by psvm():

public static void main(String[] args) {

    final ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    final SessionFactory sessionFactory = context.getBean(SessionFactory.class);
    Session session = sessionFactory.openSession();

    Book book = Book.builder().title("Peace and War").build();

    Transaction tx = session.beginTransaction();
    session.save(book);
    tx.commit();
    session.close();

    session = sessionFactory.openSession();
    book = session.get(Book.class, book.getId());
}

I've also added a plugin to maven in order to enhance bytecode:

   <build>
        <plugins>
            <plugin>
                <groupId>org.hibernate.orm.tooling</groupId>
                <artifactId>hibernate-enhance-maven-plugin</artifactId>
                <version>5.3.6.Final</version>
                <executions>
                    <execution>
                        <configuration>
                            <enableLazyInitialization>true</enableLazyInitialization>
                        </configuration>
                        <goals>
                            <goal>enhance</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
   </build>

But still, the title is fetched eagerly with the following query:

Hibernate: select book0_.id as id1_0_0_, book0_.title as title2_0_0_ from Book book0_ where book0_.id=?

that I can see because of hibernate.show_sql=true

Could you help me to figure out what I am doing wrong? Seems that the answer is on the surface but I can't spot it.

Pasha
  • 1,768
  • 6
  • 22
  • 43
  • Would this https://stackoverflow.com/questions/43749821/is-jpa-also-lazy-for-primitive-attribues help_ – Michal Sep 03 '18 at 17:55
  • 1
    If you use FetchType.LAZY, doesn't the linked object have to be annotated with @Entity? i.e. you can't use it with String. It doesn't make sense to use it with a String, otherwise there is no scenario when you would actually fetch it other than when retrieving the main object, in this case Book. – JamesB Sep 03 '18 at 17:58
  • 2
    Lazy fetching on simple types (i.e. primitives, their wrappers, string etc.) might not be supported. That normally doesn't make much sense anyways. – Thomas Sep 03 '18 at 17:59
  • Why Hibernate simply can't create a proxy of an Entity class to provide lazy loading for wrappers, string etc? – Pasha Sep 03 '18 at 18:01
  • 1
    In most cases loading properties lazily doesn't make much sense as you'd need more queries to get the properties and if you only are interested in a few of them you can always use a query like `select book.id from Book book ...` instead. – Thomas Sep 03 '18 at 18:04
  • Does this answer your question? [Spring, Hibernate, Blob lazy loading](https://stackoverflow.com/questions/2605477/spring-hibernate-blob-lazy-loading) – Martin Dec 21 '21 at 20:17

1 Answers1

3
 @Basic(fetch = FetchType.LAZY, optional = false)

According to the JPA specification @Basic Lazy loading is not guaranteed to be applied regarding which implementation you are using. you can check it here https://en.wikibooks.org/wiki/Java_Persistence/Basic_Attributes

Support for LAZY fetching on Basic is optional in JPA, so some JPA providers may not support it.

Anyway, one workaround is to create a new separated entity, say for example BookTitle, then establish a one-to-one relation and load it Lazily from the Book Entity:

public class BookTitle {
    @Id
    @GeneratedValue
    private Long id;

    @Lob
    @Basic(fetch = FetchType.LAZY, optional = false)
    private String title;
}


public class Book {

    @Id
    @GeneratedValue
    private int id;

    @OneToOne (fetch = FetchType.LAZY)
    private BookTitle bookTitle;

}