2021-09-06 JPA Hibernate 5-byte code enhanced lazy loading (invalid due to jackson serialization)

JPA Hibernate 5 lazy load

Cause: there is a large field (rich text field with base64 image) in the project. When querying the front end, you don't want every entity class to carry this field, so you try to load it lazily

The test writes a student class, where description is a large field that needs to be loaded lazily, and there are some one-to-one and one to many mapping relationships
You need to mark the @ Basic annotation on the lazy loaded field, as shown in the figure

If you want to load successfully, you need to do the following

I Bytecode enhancement plug-in

maven plug-in needs to be configured

<plugin>
    <groupId>org.hibernate.orm.tooling</groupId>
    <artifactId>hibernate-enhance-maven-plugin</artifactId>
    <version>5.4.32.Final</version>
    <executions>
        <execution>
            <configuration>
                <failOnError>true</failOnError>
                <enableLazyInitialization>true</enableLazyInitialization>
                <enableDirtyTracking>true</enableDirtyTracking>
            </configuration>
            <goals>
                <goal>enhance</goal>
            </goals>
        </execution>
    </executions>
</plugin>

After configuration, compile. The student class compiled successfully will carry the following information

As you can see, there are more in the compiled code$$_ hibernate_attributeInterceptor and other classes

Then start the run. You can interrupt the query and find

In the service layer, there are no lazy loaded fields in the queried student data (@ OneToOne annotated fields are invalid, and the reason will be checked later)
Remember to mark the @ Transactional annotation on the service layer to ensure that the session always exists

II jackson serialization triggers lazy loading of fields

Go on. There is no problem that the service returns the student of the controller, but there is a problem when the controller returns the serialization of the front end

Unable to perform requested lazy initialization [com.glaytech.domain.Teacher.description] - no session and settings disallow loading outside the Session
	at org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper.throwLazyInitializationException(EnhancementHelper.java:199) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
	at org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper.performWork(EnhancementHelper.java:89) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
	at org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor.loadAttribute(LazyAttributeLoadingInterceptor.java:76) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
	at org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor.fetchAttribute(LazyAttributeLoadingInterceptor.java:72) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
	at org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor.handleRead(LazyAttributeLoadingInterceptor.java:53) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
	at org.hibernate.bytecode.enhance.spi.interceptor.AbstractInterceptor.readObject(AbstractInterceptor.java:153) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
	at com.glaytech.domain.Teacher.$$_hibernate_read_description(Teacher.java) ~[classes/:na]

After tracing this problem, it is found that when jackson serializes the object and returns to the front end, in the serializeAsField method, in order to obtain the value of the field, the get method of the field will be called, such as getName()
However, for lazy loading, once this field is called, it will initiate sql query for this field. However, in the controller layer, because the previous transaction has been closed, the session does not exist

III jackson serialization solution:

1. The data in the object student will be returned$$_ hibernate_ The interceptor object is set to null. Once it is set to null, getName and other methods will directly return the value in the domain and will not initiate sql
2.jackson configuration takes the value directly from the field field without calling the get method of the attribute
The specific configuration is shown in the figure below

After adding the red box, you can solve the error and load it successfully

IV@ LazyGroup lazy load group

After successful lazy loading, a problem is found. As long as I get one of the lazy loading attributes, the rest will be obtained together

At this time, the @ LazyGroup annotation is needed to group the attributes

Attributes in the same lazy loading group will be loaded at the same time By default, lazy loading properties are all in the same group
LazyGroup should not be marked on the attributes of one-to-many or many to one mapping annotations (the specific reason is unclear, and it is not necessary to do so in fact, because these one-to-many to one mapping attributes will not be queried together. You still need to manually call getTeachers() method to load them, which is not affected by LazyGroup)

reference resources:
Jackson called getter method incorrectly when using:
https://blog.csdn.net/qq276291420/article/details/116520472

Bytecode enhancement:
https://www.cnblogs.com/hankuikui/p/11733877.html

Keywords: Java Hibernate Spring jpa

Added by ReignFire on Wed, 15 Dec 2021 05:56:49 +0200