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.
目前它没有回滚,因为您正在捕获块中的异常,但它应该被抛出
我在 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.
目前它没有回滚,因为您正在捕获块中的异常,但它应该被抛出