【问题标题】:What is the difference between defining @Transactional on class vs method在类与方法上定义@Transactional有什么区别
【发布时间】:2014-06-01 16:56:40
【问题描述】:

案例1

@Transactional
public class UserServiceImpl implements UserService {

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

        }
    }
    public void method2(){

    }
}

案例2

public class UserServiceImpl implements UserService {

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

        }
    }
    @Transactional
    public void method2(){

    }
}

如果发生任何异常,则在 case1 中回滚正在工作,但在 case 2 中,则无法正常工作。如果我按照 case1 进行操作,是否会出现性能问题?

【问题讨论】:

    标签: java spring spring-mvc spring-transactions


    【解决方案1】:

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

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

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

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

    案例 2: - 调用 method1() -> 没有事务开始。当 method1() 调用 method2() NO 新事务开始。这是因为 @Transactional 在从同一个类中调用方法时不起作用。如果你从另一个类中调用 method2() 就可以了。

    来自spring reference manual

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

    【讨论】:

    • 加倍警告从非注释方法调用注释方法:它不会启动事务,即使对于注释方法也是如此。另请参阅 mok 的回答。
    【解决方案2】:

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

    【讨论】:

    • 如果我注释一个类 Transactional(value="notPrimaryTransactionManager") 然后用 Transactional(readOnly=true) 注释一个成员方法,该方法将使用“notPrimaryTransactionManager”还是使用spring提供的默认事务经理?
    【解决方案3】:

    假设你有以下类:

    @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
      }
    }
    

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

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

    更多信息:

    【讨论】:

    • 但只有在 updateFoo 被外部调用时。如果 getFoo 调用 updateFoo (就像 OP 要求的那样),那么完整的事务将是只读的。
    【解决方案4】:

    引用here

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

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

    【讨论】:

    • 这里没有指出@Transactional注解方法和@Transactional注解类之间的区别。
    • @kocko> 我以为OP会关注链接,但我刚刚更新了我的答案,请看一下。
    • @mok 我正面临“自我调用不会创建事务”的问题,这个答案让我想起了我有一段时间的学习。谢谢!
    • 这并没有解释 OP 所要求的差异,而只是突出了一个用@Transactional 注释方法的问题。链接的文档现已更新。为了后代,最新的文档说:Spring 团队建议您仅使用 @Transactional 注释来注释具体类(和具体类的方法),而不是注释接口。我>
    猜你喜欢
    • 1970-01-01
    • 2017-11-08
    • 1970-01-01
    • 2012-06-23
    • 1970-01-01
    • 2020-01-23
    • 1970-01-01
    • 1970-01-01
    • 2011-06-18
    相关资源
    最近更新 更多