JPA Lazy loading is not working in Spring boot

27,691

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

Share:
27,691
Hossam Badri
Author by

Hossam Badri

Software Engineer. Passionate Java developer, and more...

Updated on July 09, 2022

Comments

  • Hossam Badri
    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.

    enter image description here

    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
    Hossam Badri about 5 years
    Thanks. But even before I click the arrow I see in the line of that attribute that already has the information
  • Sofo Gial
    Sofo Gial about 5 years
    IDEs handle debugging differently. InteliJ loads everything in advance for you, but another IDE may not.
  • Hossam Badri
    Hossam Badri about 5 years
    Even 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
    Maciej Kowalski about 5 years
    chech my upated.
  • Hossam Badri
    Hossam Badri about 5 years
    Thanks for your notice, please see the updated above
  • Hossam Badri
    Hossam Badri about 5 years
    Nice help, I'm now getting org.hibernate.LazyInitializationException: could not initialize proxy - no Session. I tried installing Hibernate5Module but did not work yet, still same error
  • Pratik Bhajankar
    Pratik Bhajankar about 5 years
    add such an answer in comments.
  • Hossam Badri
    Hossam Badri about 5 years
    precise concise and understandable
  • Alex
    Alex over 4 years
    I 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
    gagarwa almost 4 years
    You can fix this with @Transactional. See Kowalski's answer.
  • Tomasz Białecki
    Tomasz Białecki over 3 years
    Please create simple POJO (let's say AirWaybillTO and put all attributes you need there, then map them from AirWaybill and return AirWaybillTO from your service.
  • Suraj Rao
    Suraj Rao over 3 years
    Please 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
    Satish Patro over 3 years
    can 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?