Java 在类和方法上定义 @Transactional 有什么区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23132822/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 20:57:47  来源:igfitidea点击:

What is the difference between defining @Transactional on class vs method

javaspringspring-mvcspring-transactions

提问by Anil Kumar

Case1

情况1

@Transactional
public class UserServiceImpl implements UserService {

    ...................
    public void method1(){
        try{
            method2();
        }catch(Exception e){

        }
    }
    public void method2(){

    }
}

Case2

案例2

public class UserServiceImpl implements UserService {

    ...................
    public void method1(){
        try{
            method2();
        }catch(Exception e){

        }
    }
    @Transactional
    public void method2(){

    }
}

In case1 if any exception occurs it rollback is working, but in case 2 it's not working. Is there any performance issues if I follow the case1?

如果发生任何异常,则在 case1 中回滚正在工作,但在 case 2 中它不起作用。如果我遵循 case1,是否有任何性能问题?

回答by mok

Quoting from here

这里引用

The Spring team's recommendation is that you only annotate concrete classes with the @Transactional annotation, as opposed to annotating interfaces.

Spring 团队的建议是您只使用 @Transactional 注释来注释具体类,而不是注释接口。

Since this mechanism is based on proxies, only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional!

由于此机制基于代理,因此只会拦截通过代理传入的“外部”方法调用。这意味着“自调用”,即目标对象中的一个方法调用目标对象的其他方法,即使被调用的方法用@Transactional 标记,也不会在运行时导致实际的事务!

回答by jeromerg

@Transactionalon a class applies to each method on the service. It is a shortcut. Typically, you can set @Transactional(readOnly = true)on a service class, if you know that all methods will access the repository layer. You can then override the behavior with @Transactionalon methods performing changes in your model. Performance issues between 1) and 2) are not known.

@Transactional类适用于服务上的每个方法。这是一条捷径。通常,您可以设置@Transactional(readOnly = true)一个服务类,如果您知道所有方法都将访问存储库层。然后,您可以使用@Transactional在模型中执行更改的方法覆盖该行为。1) 和 2) 之间的性能问题未知。

回答by Konstantin Yovkov

Suppose you have the following class:

假设您有以下类:

@Transactional(readOnly = true)
public class DefaultFooService implements FooService {

  public Foo getFoo(String fooName) {
    // do something
  }

  // these settings have precedence for this method
  @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
  public void updateFoo(Foo foo) {
    // do something
  }
}

The @Transactionalannotation on the class level will be applied to every method in the class.

@Transactional类级别的注释将应用于类中的每个方法。

However, when a method is annotated with @Transactional(like, updateFoo(Foo foo)) this will take precedence over the transactional settings defined at the class level.

但是,当一个方法用@Transactional(如,updateFoo(Foo foo))注释时,这将优先于在类级别定义的事务设置。

More info:

更多信息:

回答by niekname

In case 1 @Transactional is applied to every public individual method. Private and Protected methods are Ignored by Spring.

如果 1 @Transactional 应用于每个公共的单独方法。Spring 会忽略私有和受保护的方法。

Spring applies the class-level annotation to all public methods of this class that we did not annotate with @Transactional. However, if we put the annotation on a private or protected method, Spring will ignore it without an error.

Spring 将类级别的注释应用于我们没有用 @Transactional 注释的这个类的所有公共方法。但是,如果我们将注解放在私有或受保护的方法上,Spring 将忽略它而不会出错。

In case 2 @Transactional is only applied to method2(), not on method1()

如果 2 @Transactional 仅适用于 method2(),而不适用于 method1()

Case 1: - Invoking method1() -> a transaction is started. When method1() calls method2() no new transaction is started, because there is already one

情况 1: - 调用 method1() -> 事务开始。当 method1() 调用 method2() 时,不会启动新的事务,因为已经有一个

Case 2: - Invoking method1() -> no transaction is started. When method1() calls method2() NOnew transaction is started. This is because @Transactional does not work when calling a method from within the same class. It would work if you would call method2() from another class.

情况 2: - 调用 method1() -> 没有事务开始。当方法1()调用方法2()启动新的事务。这是因为从同一类中调用方法时 @Transactional 不起作用。如果您从另一个类调用 method2() ,它会起作用。

From the spring reference manual:

弹簧参考手册

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, will 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 behaviour so you should not rely on this feature in your initialization code, i.e. @PostConstruct.

在代理模式下(默认),只有通过代理进入的外部方法调用才会被拦截。这意味着自调用实际上是目标对象中的一个方法调用目标对象的另一个方法,即使被调用的方法用@Transactional 标记,也不会在运行时导致实际事务。此外,代理必须完全初始化以提供预期的行为,因此您不应在初始化代码中依赖此功能,即@PostConstruct。