Spring:事务传播

时间:2017-06-20 08:34:41

标签: java spring postgresql transactions spring-transactions

我有以下代码:

@Transactional
public void handle() {
    for (Item item : getItems()) {
        handle(item);
    }
}

@Transactional(propagation = Propagation.NESTED)
public void handle(Item item) {
    /* logic here */
}

假设handle()中的循环处理10个项目。还假设对于3个项handle(Item)将抛出异常。

我的问题:

[1]外部交易是否会在第10项之后提交?这意味着将提交7个项目的必要更改,并且其他3个项目的任何中间更改将在创建时回滚到保存点?

[2] handle(Item)中的异常是否会被捕获而不会被转发到handle()呢?这是由@Transactional完成的吗?

[3]此外,我想了解以下流程的行为差异:

@Transactional
public void handle() {
    for (Item item : getItems()) {
        handle(item);
    }
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void handle(Item item) {
    /* logic here */
}

根据我对文档的理解,这里将启动一个新事务,并且将暂停活动事务。这与NESTED不同,后者创建了保存点并且仍在使用当前事务。但我相信,REQUIRES_NEW也会提交7个项目的更改,而其他3个项目的任何中间更改都将被遗忘。

那么真正的区别是什么(如果有的话)?

2 个答案:

答案 0 :(得分:2)

NESTED开始主要的子交易。 REQUIRES_NEW开始单独交易。

如果使用REQUIRES_NEW标记方法,则无论外部事务发生什么,方法退出数据都保留在DB中(由单独的事务提交)。

如果是NESTED,如果外部事务被回滚,则更改将被回滚。

查看答案here

答案 1 :(得分:1)

  

根据我对文档的理解,这里将有一个新的交易   已开始,活动交易将被暂停。

  1. 如果一个服务中的方法句柄()和句柄(项目项),则只有一个事务将被启动 - 对于第一个方法。它被称为自我调用。见:
  2. A Spring hard fact about transaction managementWHAT IS A TRANSACTION?

    在handle()内部应用handle(Item项)的事务,你应该

        @Transactional
        public void handle() {
           for (Item item : getItems()) {
             applicationContext.getBean(your service).handle(item); 
           }
        }
    
    or use spring aspectj load time weaving for self-invocation (inside one service call one method from another)
    

    在循环内使用Propagation.REQUIRES_NEW调用方法,这对性能不利,您为每个调用创建新事务。您可以在一个方法中包装但处理异常 - 仅用于与业务逻辑相关的异常!并非所有类型的例外

    @Transactional
    public void handle() {
            ..some logic
            //if you really need it
            applicationContext.getBean(your service).handleBatch(getItems());
        }
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void handleBatch(Collection items) {
        for (Item item : items) {
            applicationContext.getBean(your service).handle(item)
        }
    }
    
    public void handle(Item item) {
       try{ 
          //do operation
          }catch(.appropriate type..Exception ex){
             //log exception!!!
       }
    }
    
    1. 关于回滚:spring会在RuntimeException和Error上回滚,但不会在已检查的异常上回滚。 如果您方法抛出一些已检查的异常,则将提交更改。 避免提交使用
        

      @Transactional(的rollbackFor = CheckedException.class)