简体   繁体   中英

@Transactional works on public method in service but not with protected method

I am trying to call a service method(B) from another service method(A) from same service impl class. Now when I put @Transactional on #A, everything works fine, but when I put the same on #B everything breaks apart. And the error that I get is

Exception: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: MyEntity.childs, could not initialize proxy - no Session
        at <reference to my code>
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:685) ~[spring-aop-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at <reference to my code>
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_162]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_162]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_162]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_162]
        at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:223) ~[spring-core-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.cloud.context.scope.GenericScope$LockedScopedProxyFactoryBean.invoke(GenericScope.java:483) ~[spring-cloud-context-2.0.0.RC1.jar:2.0.0.RC1]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) ~[spring-aop-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at <reference to my code>
        at <reference to my code>
        at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590) ~[na:1.8.0_162]
        at <reference to my code>
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[na:1.8.0_162]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_162]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_162]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_162]
        at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_162]
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: MyEntity.childs, could not initialize proxy - no Session
        at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:582) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
        at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:201) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
        at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:561) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
        at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:132) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
        at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:277) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
        at <reference to my code>
        ... 24 common frames omitted

My class call structure is like this 在此处输入图片说明

A = fail case
B = success case

doProcessS() ==> public void
doSubProcessS() ==> protected void

I am using SpringBoot 2.0.0.RELEASE

I want to execute everything in 'A' way and not 'B' as I want to execute another check in doProcessS() based on data committed to DB in doSubProcess()

@Transactional is based on Spring AOP

Spring AOP does not work in self-invocation method (Within the same class)

You can fix it by mark your doProcessS() in ServiceImpl as @Transactional

Reference

This means that method calls on that object reference will be calls on the proxy, and as such the proxy will be able to delegate to all of the interceptors (advice) that are relevant to that particular method call. However, once the call has finally reached the target object, the SimplePojo reference in this case, any method calls that it may make on itself, such as this.bar() or this.foo(), are going to be invoked against the this reference, and not the proxy. This has important implications. It means that self-invocation is not going to result in the advice associated with a method invocation getting a chance to execute.

If you want to separate your transaction, delegate doSubProcessS to other class and mark it propagation type as Propagation.REQUIRES_NEW

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM