@Transactional 适用于服务中的 public 方法,但不适用于受保护的方法

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

我正在尝试从同一服务实现中的另一个服务方法 (A) 调用服务方法 (B) class。现在,当我将@Transactional 放在#A 上时,一切正常,但是当我将它放在#B 上时,一切都崩溃了。我得到的错误是

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

我的class调用结构是这样的

A = 失败案例
B = 成功案例

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

我正在使用 SpringBoot 2.0.0.RELEASE

我想以 'A' 方式而不是 'B' 执行所有操作,因为我想根据在 doSubProcess()

中提交给数据库的数据在 doProcessS() 中执行另一次检查

@Transactional 基于 Spring AOP

Spring AOP 在自调用方法中不起作用(同一个class)

您可以通过将 ServiceImpl 中的 doProcessS() 标记为 @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.

如果您想分离您的交易,请将doSubProcessS委托给其他class并将其传播类型标记为Propagation.REQUIRES_NEW