Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring@Transactional属性在私有方法上工作吗?_Java_Spring_Transactions_Annotations - Fatal编程技术网

Java Spring@Transactional属性在私有方法上工作吗?

Java Spring@Transactional属性在私有方法上工作吗?,java,spring,transactions,annotations,Java,Spring,Transactions,Annotations,如果我在Springbean中的私有方法上有一个-annotation,那么这个annotation会有任何效果吗 如果@Transactional注释位于公共方法上,它将工作并打开一个事务 public class Bean { public void doStuff() { doPrivateStuff(); } @Transactional private void doPrivateStuff() { } } ... Bean bean = (Bean

如果我在Springbean中的私有方法上有一个-annotation,那么这个annotation会有任何效果吗

如果
@Transactional
注释位于公共方法上,它将工作并打开一个事务

public class Bean {
  public void doStuff() {
     doPrivateStuff();
  }
  @Transactional
  private void doPrivateStuff() {

  }
}

...

Bean bean = (Bean)appContext.getBean("bean");
bean.doStuff();

您的问题的答案是否定的-
@Transactional
如果用于注释私有方法,则无效。代理生成器将忽略它们

这记录在:

方法可见性和
@Transactional

使用代理时,应应用 仅
@Transactional
注释 使用具有公共可见性的方法。如果 您可以对受保护、私有或 使用
@Transactional
注释,无错误 已提出,但已注释的方法 不显示已配置的 事务设置。考虑一下 如果需要,请使用AspectJ(见下文) 注释非公共方法


答案是否定的。请看 :

@Transactional
注释可以放在接口定义、接口上的方法、类定义或类上的公共方法之前


默认情况下,
@Transactional
属性仅在对从applicationContext获得的引用调用带注释的方法时起作用

public class Bean {
  public void doStuff() {
    doTransactionStuff();
  }
  @Transactional
  public void doTransactionStuff() {

  }
}
这将打开一个事务:

Bean bean = (Bean)appContext.getBean("bean");
bean.doTransactionStuff();
这不会:

Bean bean = (Bean)appContext.getBean("bean");
bean.doStuff();

注意:在代理模式(这是默认模式)下,只有通过代理传入的“外部”方法调用才会被拦截。这意味着“自调用”,即目标对象内调用目标对象其他方法的方法,即使调用的方法标记为
@Transactional
,在运行时也不会导致实际事务

如果您希望使用事务包装自调用,请考虑使用AspectJ模式(见下文)。在这种情况下,首先不会有代理;相反,目标类将被“编织”(即其字节码将被修改),以便将
@Transactional
转换为任何类型方法的运行时行为


春季医生解释说

在代理模式(默认)下,只有外部方法调用 通过代理进入被拦截。这意味着 自调用,实际上是目标对象中调用 目标对象的另一种方法,不会导致实际的 即使调用的方法标记为 @事务性的

考虑使用AspectJ模式(参见下表中的模式属性) 如果您希望将自调用与事务打包为 好。在这种情况下,首先不会有代理人; 相反,将编织目标类(即,其字节码将 要将@Transactional转换为上的运行时行为 任何一种方法


另一种方法是用户BeanSelfAware

问题不是私有的或公共的,问题是:如何调用它以及使用哪种AOP实现

如果使用(默认)Spring代理AOP,则只有在调用通过代理时才会考虑Spring提供的所有AOP功能(如
@Transactional
)如果从另一个bean调用带注释的方法,则通常会出现这种情况

这有两个含义:

  • 因为私有方法不能从另一个bean调用(反射是例外),所以不考虑它们的
    @Transactional
    注释
  • 如果该方法是公共的,但它是从同一个bean调用的,那么也不会考虑它(只有在使用(默认)Spring代理AOP时,该语句才是正确的)
@看


我想您应该使用aspectJ模式,而不是Spring代理,这将克服这个问题。AspectJ事务方面甚至被编织到私有方法中(选中Spring 3.0)。

是的,可以在私有方法上使用@Transactional,但正如其他人所提到的,这并不是现成的。您需要使用AspectJ。我花了一些时间想办法让它工作。我将分享我的结果

我选择使用编译时编织而不是加载时编织,因为我认为这是一个更好的选择。另外,我正在使用Java8,因此您可能需要调整一些参数

首先,添加aspectjrt的依赖项

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.8</version>
</dependency>
现在,您应该能够在私有方法上使用@Transactional


这种方法有一个警告:您需要将IDE配置为了解AspectJ,否则,如果您通过Eclipse运行应用程序,例如,它可能无法工作。确保对直接Maven构建进行测试,作为一种健全性检查。

如果需要在事务中封装私有方法,并且不想使用aspectj,可以使用

与使用相同的方法可以使用此帮助器组件(Kotlin):


不知道
TransactionTemplate
是否重用现有事务,但此代码肯定会这样做。

您确定吗?如果代理样式是Cglib呢?你是说bean=newbean();?不。如果我使用new Bean()创建Bean,那么至少在不使用Aspect-J的情况下,注释将无法工作。谢谢!这解释了我观察到的奇怪行为。这种内部方法调用限制非常违反直觉……这两点不一定都是正确的。第一个是不正确的-可以反射地调用私有方法,但代理发现逻辑选择不这样做。第二点仅适用于基于接口的JDK代理,但不适用于基于CGLIB子类的代理。@skaffman:1-我的陈述更精确,2。但是默认代理是基于接口的,不是吗?这取决于目标是否使用接口。如果没有,就使用CGLIB。你能告诉我CGLIB不能不使用方面的原因或参考资料吗
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.8</version>
    <configuration>
        <complianceLevel>1.8</complianceLevel>
        <source>1.8</source>
        <target>1.8</target>
        <aspectLibraries>
            <aspectLibrary>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
            </aspectLibrary>
        </aspectLibraries>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
            </goals>
        </execution>
    </executions>
</plugin>
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
@Service
public class MyService {

    @Autowired
    private TransactionTemplate transactionTemplate;

    private void process(){
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                processInTransaction();
            }
        });

    }

    private void processInTransaction(){
        //...
    }

}
@Component
class TransactionalUtils {
    /**
     * Execute any [block] of code (even private methods)
     * as if it was effectively [Transactional]
     */
    @Transactional
    fun <R> executeAsTransactional(block: () -> R): R {
        return block()
    }
}
@Service
class SomeService(private val transactionalUtils: TransactionalUtils) {

    fun foo() {
        transactionalUtils.executeAsTransactional { transactionalFoo() }
    }

    private fun transactionalFoo() {
        println("This method is executed within transaction")
    }
}