3

The context of this question is within spring-boot, using spring-data-jpa and hibernate.

A colleague wrote an @Service and annotated the service method with @Transactional. The service method loads an entity, and subsequently hits a one-to-many lazily loaded collection (fetch = FetchType.LAZY). The service method is invoked by some custom delegator, which i will come back to. This works fine when invoked from a @RestController endpoint.

When i invoked the service from a camel route (again via the custom delegator) it barfed with a lazy initialization exception.

On digging, found that the service implements an interface, the custom delegator looks up the service (it is injected so has proper proxy) and calls a method on the interface which is actually a java-8 default method. This default-method then locally calls the @Transactional method.

So there's the problem :- this is a LOCAL method call so the aspecting/proxy-ing of the @Transactional annotation is not done (we use aspectJAutoProxy) so the method is NOT invoked within a transaction, so the lazy-loading SHOULD fail. And to double-check, also tried it via an @Scheduled annotation: same behaviour. Barfs like it should.

My Question: So why does it work when called from the @RestController? This is driving me nuts!

There is no transactional annotation on the rest controller endpoint.

I added some debug code to the service using TransactionSynchronizationManager.isActualTransactionActive() and it shows that in no case is there a transaction, even when being called via the controller endpoint.

So why does the lazy loading work when being called from the controller? I dumped all SQL and at no points are the lazy-collection already loaded, so they are not in any hibernate cache.

I remember reading once that lazy loading was a hint, not a command, but still... why does it work in that one case?

5
  • are u using Open session in View (OSIV)? Commented Mar 22, 2017 at 19:44
  • thanks Ali, not using OSIV. There is a filter that loads authenticated user specified in a header from the database, but that transaction closes before rest controller code executes. And to verify, TransactionSynchronisationManager.isActualTransactionActive() in the service says false. Commented Mar 22, 2017 at 20:57
  • did you find an answer Richard? It bugs me too. I have a dao layer where i load stuff and when I iterate through that in my controller it lazy loads instead of failing (which i want) Commented Oct 27, 2017 at 9:26
  • Sorry Mario, have never found the time to solve this. And all that guff in original question about java8 default methods had nothing to do with. I have subsequently encountered the same problem in the simplest possible case: lazy-loading works via a rest controller when it shouldn't; and it doesn't work via other code paths (which is good). Commented Oct 30, 2017 at 5:24
  • @MarioB answer found! Commented Jun 14, 2018 at 2:15

2 Answers 2

1

When your method annotate to transactional hibernate session close after return method , if object that return from method have lazy , lazy property not load and you get exception that session close. You can use fetch in query or using OSIV

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Ali i understand that. i'm not asking why lazily-loading is failing. i'm asking why it is working from one specific code path (via spring-rest-controller) where as far as i can tell, it shouldn't work.
1

after being perplexed by this on many occasions, have stumbled across the answer:

sprint-boot is doing an open-entity-manager-in-view behind our backs via the OpenEntityManagerInView interceptor. Had no idea this was going on.

See this excellent answer from Vlad Mihalcea https://stackoverflow.com/a/48222934/208687

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.