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