【问题标题】:@Transactional does not work on method level@Transactional 在方法级别不起作用
【发布时间】:2013-09-06 13:31:15
【问题描述】:

我有一个关于 Spring 3.2.3 @Transactional 注释的问题。 我的服务类如下所示:

@Service @Transactional
class InventoryDisclosureBO {

@Autowired InventoryDisclosureDAO inventoryDisclosureDAO;

private static final Logger log = LoggerFactory.getLogger( InventoryDisclosureBO.class);

public void processDisclosureData(InventoryDisclosureStatus data){
  validate(data);
  persist(data);
}

@Transactional(propagation = REQUIRES_NEW)
void persist(InventoryDisclosureStatus data) {
  inventoryDisclosureDAO.setAllInvalid( data.getUnit());
  inventoryDisclosureDAO.insert( data );
}

void validate(InventoryDisclosureStatus data) {
 ...
}
}

如果我调用persist() 方法,一切都会完美运行。但是,如果我在类级别注释掉 @Transactional - 事务不会开始。 谁能告诉我为什么 Spring 只能在甲醇级别忽略 @Transactional?

【问题讨论】:

    标签: java spring transactions


    【解决方案1】:

    您不能从 processDisclosureData() 调用 persist(),因为它属于同一类,并且它将绕过 Spring 为 InventoryDisclosureBO 创建的事务代理。您应该从其他 bean 调用它以使 @Transactional 注释工作。当 Spring 向其他 bean 注入对 InventoryDisclosureBO bean 的引用时,它实际上注入了对包含事务逻辑的 InventoryDisclosureBOProxy 的引用,例如

        class Bean2 {
    
          @Autowire
          private InventoryDisclosureBO idbo;   <-- Spring will inject a proxy here
    
          public void persist(InventoryDisclosureStatus data) {
               idbo.persist(data);     <-- now it will work via proxy
          }
    ...
    

    【讨论】:

    • 谢谢Evgeniy,这是有道理的!如果我只将@Transactional 放在 processDisclosureData() 方法上 - 它可以完美运行。
    • 1) 您能否在您的回答中详细说明“persist() 将绕过 Spring 为 InventoryDisclosureBO 创建的事务代理”
    • 2) idbo.persist(data);
    • @Naroji 在上下文 InventoryDisclosureBO 和 InventoryDisclosureBOProxy 中会有 2 个 bean(实名不同)。后者由 Spring 创建,包含事务逻辑和对 InventoryDisclosureBO 的引用。当我们调用 InventoryDisclosureBOProxy.persist 时,它会启动事务,然后调用 InventoryDisclosureBO.persist。如果我们直接调用 InventoryDisclosureBO.persist 就不会有交易
    • @EvgeniyDorofeev 谢谢,还有一个问题 private InventoryDisclosureBO idbo;
    【解决方案2】:

    这与spring如何生成事务代理有关。

    如果你在类级别有@Transactional,当你调用InventoryDisclosureBO.processDisclosureData()时,实际上你是在调用一个启动事务的Spring代理,然后调用真正的实现。

    如果persis()中只有@Transaction,当你调用InventoryDisclosureBO.processDisclosureData()时spring不会启动事务,然后就检测不到你调用了InventoryDisclosureBO.persist()

    所以Spring基本上忽略了persist上的注解,因为它不能添加事务代理。

    根据经验,@Transactional 注释应该在公共方法上,并且希望在调用层次结构中相当高(否则每个持久化最终都会创建一个新事务)

    您可能会找到有关其他 SO 问题的更多信息:Method Interceptor on private methods(任何非公共方法的行为方式都相同)

    【讨论】:

    • 如果@Transactional在类级别应用,那么spring才会生成事务的代理?
    • 如果@Transactional 没有在类级别和 processDisclosureData 方法上应用,那么为什么它无法检测到您调用了 InventoryDisclosureBO.persist() ?
    猜你喜欢
    • 2021-01-31
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多