Spring 引导事务未回滚

Spring Boot Transaction not rolling back

我在 Spring Boot 中配置了一个项目注释。 pom 具有依赖项 spring-data-jpa 和 spring-tx.

Config class 或属性中没有关于事务配置的内容(因为理论上不需要)。

鉴于此服务:

package com.appserver.motion.service;

@Component(value = "exerciseService")
@Service
@Data
public class ExerciseService {

@Autowired private ExerciseRepository exerciseRepository;
@Autowired private TagRepository tagRepository;
@Autowired private ExerciseTagJoinRepository exerciseTagJoinRepository;
@Autowired private EquipmentRepository equipmentRepository;
@Autowired private ExerciseEquipmentJoinRepository exerciseEquipmentJoinRepository;

private ExerciseCommand exerciseCommand = new ExerciseCommand();

private List<SelectItem> tags = new ArrayList<SelectItem>();
private List<Integer> selectedTags = new ArrayList<Integer>();

private List<SelectItem> equipments = new ArrayList<SelectItem>();
private List<Integer> selectedEquipments = new ArrayList<Integer>();

@Transactional
public int saveExercise() {
    try {
        int resultat = exerciseRepository.save(toEntity()).getExe_id();

        if (this.selectedTags!=null) {
            for (Integer selectedTag: this.selectedTags) {
                ExerciseTagJoinEntity etje = new ExerciseTagJoinEntity();
                etje.setExa_exe_id(new Integer(resultat));
                etje.setExa_tag_id(new Integer(selectedTag));
                exerciseTagJoinRepository.save(etje);
            }
        }


        if (this.selectedEquipments!=null) {
            for (Integer selectedEqu: this.selectedEquipments) {
                ExerciseEquipmentJoinEntity eeje = new ExerciseEquipmentJoinEntity();
                eeje.setEeq_exe_id(new Integer(resultat));
                eeje.setEeq_equ_id(new Integer(selectedEqu));
                exerciseEquipmentJoinRepository.save(eeje);
            }
        }

        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Info:", "Insertat correcte");
        FacesContext.getCurrentInstance().addMessage("Correcte:", facesMsg);

        return resultat;
    }catch (Exception ex) {
        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error:", ex.getMessage());
        FacesContext.getCurrentInstance().addMessage("Error:", facesMsg);
        return -1;
    }
}

}

存储库都是 JpaRepository 的扩展,并用@Repository 注释。

问题是事务不回滚异常,有或没有 rollBackFor 属性

另一方面,事务似乎在工作,因为在 save 方法结束之前插入不会刷新到数据库中。

顺便说一句,我正在使用 PostgreSQL 数据库。

我遗漏了什么吗?

我一直在记录交易包,这就是我得到的:

2019-11-15 08:52:45.493 TRACE 9100 --- [nio-3000-exec-4] o.s.t.i.TransactionInterceptor : Getting transaction for [com.appserver.motion.service.ExerciseService.saveExercise] 2019-11-15 08:52:47.678 TRACE 9100 --- [nio-3000-exec-4] o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 2019-11-15 08:52:48.015 TRACE 9100 --- [nio-3000-exec-4] o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 2019-11-15 08:52:49.163 TRACE 9100 --- [nio-3000-exec-4] o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 2019-11-15 08:52:49.168 TRACE 9100 --- [nio-3000-exec-4] o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 2019-11-15 08:52:49.168 TRACE 9100 --- [nio-3000-exec-4] o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 2019-11-15 08:52:49.171 TRACE 9100 --- [nio-3000-exec-4] o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save] 2019-11-15 08:53:02.439 TRACE 9100 --- [nio-3000-exec-4] o.s.t.i.TransactionInterceptor : Completing transaction for [com.appserver.motion.service.ExerciseService.saveExercise]

您的 @Transactional 方法不会抛出异常,因为您捕获并处理了它,因此不会发生回滚。

如果您想捕获异常 - 例如用于记录目的 - 那么您可以重新抛出异常。此外,只有从 java.lang.RuntimeException.

扩展的异常才会自动发生回滚
//if the runtime type of Exception is a checked exception then optional config
@Transactional(rollbackFor = SomeNonRunTimeException.class))
public int saveExercise() {
    try {
        ....
    }catch (Exception ex) {
        //do some logging
        throw ex; //otherwise no rollback
    }
}

另一方面,事务似乎在工作,因为在保存方法结束之前插入不会刷新到数据库中。

这与事务无关,但由于 'write behind' 模式延迟刷新对数据库的更改,直到尽可能晚 - 通常在事务提交时,即当您的 @Transactional 方法 returns

http://learningviacode.blogspot.com/2012/02/write-behind-technique-in-hibernate.html

此模式导致另一个问题 - 您的异常处理程序不会捕获在刷新时生成的异常,因为刷新发生在事务提交时,即在方法 return 上 - 在您的 catch 块之外。如果你想捕获并处理这些异常,那么你需要在你的 catch 块中进行显式刷新:

@Transactional(rollbackFor = SomeNonRunTimeException.class))
public int saveExercise() {
    try {
        //explicit flush required if we want to ctach and handle SQL exceptions
        exerciseTagJoinRepository.saveAndFlush(etje);
    }catch (Exception ex) {
        //do some logging
        throw ex; //otherwise no rollback
    }
}

可能您需要从一个方法中抛出 RuntimeException,它应该被标记为

@Transactional(rollbackFor=Exception.class)

它应该回滚事务。

在你的情况下,它应该是这样的

    @Transactional(rollbackFor=FacesMessageException.class)
public int saveExercise() {
    try {

    }catch (Exception ex) {
        throw new FacesMessageException();
    }
}

我建议您应该抛出异常而不是捕获异常,例如 FacesMessageException(),但在此之前您需要创建 FacesMessageException class.

目前它没有回滚,因为您正在捕获块中的异常,但它应该被抛出