0

I have an SpringBootApp with embedded Derby;works fine. When I implement CommandLineRunner or @PostConstruct I get above error

"org.hibernate.LazyInitializationException failed to lazily initialize a collection of role:...- could not initialize proxy - no Session".

How do I create a session with Hibernate before the app actually runs but after the applications.properties file has been loaded? Also what is SprinBoot doing elsewhere that prevents this error in normal running?

 @Component
@Transactional
public class DatabaseTesting01 {
    private static Logger logger = LoggerFactory.getLogger(DatabaseTesting01.class);
    @Autowired
    EDITypeService ediTypeService;
    @Autowired
    VendorService vendorService;
    @Autowired
    SubscriberService subscriberService;
    @PostConstruct
    public void init(){
        Vendor v = vendorService.findOneByShortName("UNFI");
        logger.debug("Vendor:UNFI"+v.toString());
    }
}

UPDATE This is what worked.HTH.

@Component
@Service("database01")
public class Database01 {
    private static Logger logger = LoggerFactory.getLogger(Database01.class);
    @Autowired
    @Qualifier("transactionManager")
    protected PlatformTransactionManager txManager;
    @Autowired VendorService vendorService;

    @PostConstruct
    private void init(){
        TransactionTemplate tmpl = new TransactionTemplate(txManager);
        tmpl.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                vendorService.deleteAll();
            }
        });
    }
}
cp.
  • 1,241
  • 5
  • 15
  • 26

1 Answers1

1

The only thing the @Transactional does over the class is applying transactional functionality (creating proxy, etc) to all public methods. So you should not rely on the initialization code such as @PostConstruct. Here is the appropriate spring reference

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation (in effect, a method within the target object calling another method of the target object) does not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behavior, so you should not rely on this feature in your initialization code (that is, @PostConstruct).

UPD

In your case the main problem is a loading of a one-to-many list of roles of the vendor. And it is a predictable behaviour because of the transaction absence. I hope this topic will help you to workaround a problem, but anyway just ask yourself - is it really necessary to do such a things in a @PostCunstruct? If not, you can just implement an alternative method in the repository, using projections or a jpql constructor to get rid of joined entities loading

Yuriy Tsarkov
  • 2,461
  • 2
  • 14
  • 28
  • Thank you. However how do I configure a CommandLineRunner or @PostConstruct to properly configure for database service use? I was using http://zetcode.com/springboot/commandlinerunner/. Also where in SpringBoot does it configure properly? To just better understand architeture. – cp. Sep 11 '20 at 22:35
  • Thank you, your first reference in your above clarification worked. I updated my original for future searchers. This is "good" what is "better" or "best"? This is only for testing. Should I populate the db as a separate test run or like this and just comment out the @Component? – cp. Sep 13 '20 at 01:00
  • In general you can easily remove the `@Component` because instantiation is already provided within the `@Service` implementation, however the best way is to use [integration tests](https://www.baeldung.com/spring-boot-testcontainers-integration-test) for a test purposes – Yuriy Tsarkov Sep 13 '20 at 06:40