使用try catch,Spring @Transactional anotation无法在for循环中工作

Md.*_*rim 1 java spring hibernate spring-data-jpa spring-boot

我的问题如下.伪代码如下:

public Object rollBackTestMainMethod(List<Object> list) {

  List<Object> responseList = new ArrayList<>();

  for(Object item:list){

    try{    
      Boolean isOperationSuccess = rollBackTestSubMethod(item);
      if (isOperationSuccess==null || !isOperationSuccess){
        item.addError("Operation failed");
        item.addSuccess(false);
      } else {
        item.addError(null);
        item.addSuccess(true);
      }

    } catch(Exception exception) {
      item.addError(exception.getMessage());
      item.addSuccess(false);
    }

    responseList.add(item);
  }

  return responseList;
}

@Transactional(rollbackFor = {Exception.class, SQLException.class})
private Boolean rollBackTestSubMethod(Object listItem){

  Long value1=save(listItem.getValue1());
  if(value1==null){
    throw new Exception("Error during save 1");
  }

  Long value2=save(listItem.getValue2());
  if(value2==null){
    throw new Exception("Error during save 2");
  }
  Long value3=save(listItem.getValue3());
  if(value3==null){
    throw new Exception("Error during save 3");
  }

  return Boolean.TRUE;
}
Run Code Online (Sandbox Code Playgroud)

我在这做什么:

  1. 迭代一个列表rollBackTestMainMethod().发送一个列表项rollBackTestSubMethod()并执行3保存操作.
  2. 如果全部保存完成然后返回真实响应,否则抛出异常.
  3. rollBackTestMainMethod()获得响应或异常后,它会在每个项目上添加错误或成功值.
  4. 它将此项添加到名为的新列表中responseList.在所有操作之后,它将作为响应发回.

我的问题:

  1. rollBackTestSubMethod()它抛出之后将不会回滚,因为它是从try catch块调用的.
  2. 如果我想强制回滚,TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();那么它将回滚所有项目以进行任何抛出/异常.
  3. 在这里,我只想回滚项目而不是所有项目.
  4. 这个方法是在一个spring bean中
  5. 我通过spring数据jpa将数据保存到我的关系数据库中

我的进口:

import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
Run Code Online (Sandbox Code Playgroud)

And*_*cus 8

这是因为你@Transactional从同一个bean中调用方法.

@Transactional仅适用于在spring创建的代理上调用的方法.这意味着,当您创建一个@Service或其他bean时,从外部调用的方法将是事务性的.如果从bean内部调用,则不会发生任何事情,因为它不会通过代理对象.

最简单的解决方案是将方法移动到另一个@Service或bean.如果你真的想把它保存在同一个组件中,那么你需要调用它,以便它通过spring AOP包装在代理中.你可以这样做:

private YourClass self;

@Autowired
private ApplicationContext applicationContext;

@PostConstruct
public void postContruct(){
    self = applicationContext.getBean(YourClass.class);
}
Run Code Online (Sandbox Code Playgroud)

然后调用方法self将导致打开事务.