2

I have a SpringBoot app using SpringData to persist data on an Oracle DB and spring-boot-starter-activemq to handle JMS queues.

I am exposing a DELETE Rest WebService which takes a while. And I don't want my users to hang on the response.

So I added a method annotated with @JmsListener which does the job and I'm calling it with jmsTemplate.convertAndSend().

But if the findAll() part of my treatment works perfectly, as soon as I am trying to access data (simply displaying it for example) retrieved with the findAll() method I'm facing LazyLoadingException on my lazy collections, saying I have no Hibernate session. org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: ..., could not initialize proxy - no Session

Here is a snippet of my code if that helps:

   public void myMethod(int batchSize) {
    // Send a JMS message with a POJO
    LOGGER.trace("Calling JMS method...");
    final JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
    jmsTemplate.convertAndSend("runJob", batchSize);
}

@JmsListener(destination = "runJob")
private void runJob(final int batchSize) {
    LOGGER.debug("Calling runJob with batchSize {}", batchSize);
    List<MyEntity> myEntities = myRepository.findAll();
    LOGGER.debug("{} entities retrieved from the DB", myEntities.size()); // Prints the actual number of entities in my DB
    for(Entity entity : entities){
        LOGGER.debug("Entity name {}", entity.getName()); // Prints entity name
        LOGGER.debug("Entity first collection's value {}", entity.getMyList().get(0).toString()); // org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: ..., could not initialize proxy - no Session
    }
}

// -----------------------
// Full code of my repository -> The implementation is generated by spring-data http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
public interface MyRepository extends org.springframework.data.jpa.repository.JpaRepository<MyEntity, Long>{}

I just would like to know how to keep my session attached to my Jms method.

Cheers, Olivier

Olivier
  • 1,524
  • 1
  • 18
  • 27
  • 2
    Don't describe your code and your exception. Post them. – JB Nizet Nov 08 '16 at 17:48
  • @JBNizet just added a code snippet. By the way, the exception was listed in my initial post (LazyLoadingException on my lazy collections) and the code (display data) was also there. I though I could focus on what is truly important: the problem rather than pure code. Any way, here it is. – Olivier Nov 09 '16 at 07:56

1 Answers1

0

Your JmsListener method is processed asynchronously (that's the whole point of why you're doing this) so it's running on a different thread. If it's running on a different thread, you can't use the same transaction.

You can, however, start a new transaction when the JMS message will be processed but you have to realize what that concretely means. Adding @Transactional on runJob should do it. Because it is now asynchronous, you have to take that into account in the response. What HTTP status code are you going to return. Something may fail in the background for instance.

Stephane Nicoll
  • 27,654
  • 7
  • 72
  • 70
  • thanks for reply. I agree 100% with you concerning the goal of async process. Of course, I'm not trying to have `runJob` and `myMethod` running in the same transaction, for sure. I just want `runJob` not to close the Hibernate session after calling `myRepository.findAll()`. I forgot to mention it, but yes, I tried to make `runJob` `@Transactional` but have not success. Like you, I though it would do it... And I can't understand how a method could be `@Transactional` if it closes its `session` while running... By the way, I have few more code so one can know what the JMS method already did. – Olivier Nov 10 '16 at 10:48
  • your method is private, it must be public in order to have it proxied for transaction purpose. I am actually surprised private works at all for `@JmsListener` – Stephane Nicoll Nov 10 '16 at 10:59
  • I'm sorry, but it does not solve the problem. I was sure it would but... I'm still facing the exact same problem, while I made all my methods `public`. – Olivier Nov 15 '16 at 13:59
  • I am afraid I can't help you with partial code snippet. There is something else in the code that makes it fail but I don't know what. Can you share a sample? – Stephane Nicoll Nov 15 '16 at 14:15
  • Alright. I must create another project then. I of course can't share my whole project. By the way, I was planning to do this to isolate the problem. I simply need some time to do this... I'll do my best to create that quickly. – Olivier Nov 17 '16 at 08:24