首页 > 解决方案 > 回滚不适用于多个插入

问题描述

Application 类内部方法上的@Transactional 注释不会回滚插入。但是,服务类(EmpService.java) 方法("insertEmp(Emp emp)") 上的@Transactional 注释按预期工作。

有人可以让我知道为什么@Transactional 的工作方式不同吗?Spring Boot 版本 - 2.1.3.RELEASE 与 h2 数据库。如果需要任何其他信息,请告诉我。

@SpringBootApplication
@ComponentScan("org.saheb")
@EnableJpaRepositories("org.saheb.repo")
@EntityScan("org.saheb.vo")
@EnableTransactionManagement
public class SpringJpaTransactionApplication implements CommandLineRunner {
@Autowired
private EmpService empService;

public static void main(String[] args) {
    SpringApplication.run(SpringJpaTransactionApplication.class, args);
}

@Override
public void run(String... args) throws Exception {
    insertSingleBatch();
}
@Transactional(rollbackFor=RuntimeException.class, propagation=Propagation.REQUIRES_NEW)
public void insertSingleBatch() {
    try {
        Set<Emp> empSet = new LinkedHashSet<>();
        Dept dept = new Dept();
        dept.setDeptNo(10);
        empSet.add(new Emp("abc", "abc", dept));
        empSet.add(new Emp("xyz", "xyz", dept));
        empSet.add(new Emp("def", "def", dept));
        empSet.add(new Emp("pqrstu", "pqr", dept));// This will fail as max character allowed in 5 and should rollback all the insertion. But, first three records are getting saved in h2 database.
        empService.insertEmp(empSet);
    } catch (RuntimeException e) {
        System.out.println("Exception in batch1.." + e.getMessage());
    }
}
}

@Service
public class EmpService {
@Autowired
private EmpRepository empRepository;

//@Transactional(rollbackFor=RuntimeException.class, propagation=Propagation.REQUIRES_NEW)//This is working as expected as all the insertions are rolling back after failure of 4th insertion
public void  insertEmp(Set<Emp> empSet) {
    System.out.println("Inside insert");
    for (Emp temp : empSet) {
        Emp temp2 =empRepository.save(temp);
        System.out.println("inserted-->"+temp2.getFirstName());
    }
}
}

标签: spring-bootjpaspring-transactions

解决方案


您是来自同一个 bean 的“自我调用”@Transactional方法,该方法不起作用。此行为在此处此处的文档中得到了很好的解释(搜索关键字“自我调用”)

您可以简单地将@Transactional方法移动到另一个 bean。然后将此 bean 注入其客户端 bean 并调用此@Transactional方法。

或者使用TransactionTemplate在事务中执行它:


   @Autowired
   private TransactionTemplate txTemplate;

   @Override
   public void run(String... args) throws Exception {
            txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            txTemplate.execute(status->{
                insertSingleBatch();
                return null;
            });

   }

请注意,这TransactionTemplate将忽略 上的设置@Transactional,您必须以编程方式对其进行配置。


推荐阅读