JPA Lazy loading is not working in Spring boot
Solution 1
Hibernate Session exists within method with @Transactional
.
Passing entity outside Service class is a bad practise because session is being closed after leaving your search
method. On the other hand your entity contains lazy initialised collections, which cannot be pulled once session is closed.
The good practise is to map entity onto transport object and return those transport objects from service (not raw entities).
Solution 2
SpringBoot by default has enabled:
spring.jpa.open-in-view = true
That means transaction is always open. Try to disable it.
more information here
Solution 3
Most likely you are debugging while still being inside the service, thus while the transaction is still active and lazy loading can be triggered (any method called on a lazy element triggered the fetch from the database).
The problem is that lazy loading cannot occur while being outside of the transaction. And Jackson is parsing your entity definitely outside the boundaries of one.
You either should fetch all the required dependencies when building your specification or try with the @Transactional
on the resource level (but try that as of last resort).
Just so that you know, LAZY fetching strategy is only a hint.. not a mandatory action. Eager is mandatory:
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.
Solution 4
When using a debugger, you are trying to access the value of your variables. So, at the moment you click that little arrow on your screen, the value of the variable in question is (lazily) loaded.
Solution 5
Just a guess: you are forcing a fetch while building your specification.
I expect something like
static Specification<AirWaybill> buildSpec() {
return (root, query, criteriaBuilder) -> {
Join<AirWaybill, CorporateBranch> br = (Join) root.fetch("corporateBranch");
return criteriaBuilder.equal(br.get("addressType"), 1);
};
}
If this is the case, try changing root.fetch
to root.join
Hossam Badri
Software Engineer. Passionate Java developer, and more...
Updated on July 09, 2022Comments
-
Hossam Badri almost 2 years
I googled a lot and It is really bizarre that Spring Boot (latest version) may not have the lazy loading is not working. Below are pieces of my code:
My resource:
public ResponseEntity<Page<AirWaybill>> searchAirWaybill(CriteraDto criteriaDto, @PageableDefault(size = 10) Pageable pageable{ airWaybillService.searchAirWaybill(criteriaDto, pageable); return ResponseEntity.ok().body(result); }
My service:
@Service @Transactional public class AirWaybillService { //Methods public Page<AirWaybill> searchAirWaybill(AirWaybillCriteriaDto searchCriteria, Pageable pageable){ //Construct the specification return airWaybillRepository.findAll(spec, pageable); } }
My Entity:
@Entity @Table(name = "TRACKING_AIR_WAYBILL") @JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@airWaybillId") //to fix Infinite recursion with LoadedAirWaybill class public class AirWaybill{ //Some attributes @NotNull @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "FK_TRACKING_CORPORATE_BRANCH_ID") private CorporateBranch corporateBranch; }
And when debugging, I still getting all lazy loaded attributed loaded. See image below.
One of my questions is could Jackson be involved in such behaviour? Is there any way that I may have missed to activate the lazy loading?
EDIT
Another question, could the debugger be involved in ruining the lazy loading?
EDIT 2:
For specification build, I have :
public static Specification<AirWaybill> isBranchAirWayBill(long id){ return new Specification<AirWaybill>() { @Override public Predicate toPredicate(Root<AirWaybill> root, CriteriaQuery<?> query, CriteriaBuilder cb) { return cb.equal(root.join("corporateBranch",JoinType.LEFT).get("id"),id); } }; }
-
Hossam Badri about 5 yearsThanks. But even before I click the arrow I see in the line of that attribute that already has the information
-
Sofo Gial about 5 yearsIDEs handle debugging differently. InteliJ loads everything in advance for you, but another IDE may not.
-
Hossam Badri about 5 yearsEven when I see the response in my browser I see the all lazy loaded attributes are loaded (which I don't like to). So the debugger has nothing to do with the loaded children
-
Maciej Kowalski about 5 yearschech my upated.
-
Hossam Badri about 5 yearsThanks for your notice, please see the updated above
-
Hossam Badri about 5 yearsNice help, I'm now getting
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
. I tried installingHibernate5Module
but did not work yet, still same error -
Pratik Bhajankar about 5 yearsadd such an answer in comments.
-
Hossam Badri about 5 yearsprecise concise and understandable
-
Alex over 4 yearsI am sorry, but I don't understand it. Do you have an example somewhere showing how this transport design is setup? Thank you in advance
-
gagarwa almost 4 yearsYou can fix this with @Transactional. See Kowalski's answer.
-
Tomasz Białecki over 3 yearsPlease create simple POJO (let's say
AirWaybillTO
and put all attributes you need there, then map them fromAirWaybill
and returnAirWaybillTO
from your service. -
Suraj Rao over 3 yearsPlease add code and data as text (using code formatting), not images. Images: A) don't allow us to copy-&-paste the code/errors/data for testing; B) don't permit searching based on the code/error/data contents; and many more reasons. Images should only be used, in addition to text in code format, if having the image adds something significant that is not conveyed by just the text code/error/data.
-
Satish Patro over 3 yearscan someone explain this annotation. in Documentation, it is not properly explained. baeldung.com/hibernate-lazy-loading-workaround after reading this article, it seems @ Transactional is better, but if we add "enable_lazy_load_no_trans" then it will call for list of object & each object each refered lazy object in one trasnaction per object. Is @LazyToOne also will do one time one transaction or is it one extra txn in total only?