[SPRING] JPA 트랜잭션을 커밋 할 수 없음 : rollbackOnly로 표시된 트랜잭션
SPRINGJPA 트랜잭션을 커밋 할 수 없음 : rollbackOnly로 표시된 트랜잭션
Spring과 Hibernate를 사용하고있는 어플리케이션 중 하나에서 트랜잭션을 처리하는 데 문제가 있습니다.
데이터베이스에서 일부 엔티티를로드하고 일부 값을 수정 한 다음 (모든 것이 유효한 경우) 데이터베이스에 이러한 변경 사항을 커밋하는 서비스 클래스가 있습니다. 새 값이 유효하지 않은 경우 (설정 한 후에 만 확인할 수 있음) 변경 사항을 유지하고 싶지 않습니다. Spring / Hibernate가 변경 사항을 저장하는 것을 막기 위해 메소드에서 예외가 발생합니다. 그러나 다음과 같은 오류가 발생합니다.
Could not commit JPA transaction: Transaction marked as rollbackOnly
그리고 이것은 서비스입니다.
@Service
class MyService {
@Transactional(rollbackFor = MyCustomException.class)
public void doSth() throws MyCustomException {
//load entities from database
//modify some of their values
//check if they are valid
if(invalid) { //if they arent valid, throw an exception
throw new MyCustomException();
}
}
}
그리고 이것이 내가 그것을 호출하는 방법입니다 :
class ServiceUser {
@Autowired
private MyService myService;
public void method() {
try {
myService.doSth();
} catch (MyCustomException e) {
// ...
}
}
}
내가 기대할 수있는 것 : 데이터베이스에 변경 사항이없고 사용자에게 보이는 예외도 없습니다.
어떤 일이 일어나는가 : 데이터베이스에 변화가 없지만 앱이 충돌 함 :
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction;
nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
트랜잭션을 rollbackOnly로 올바르게 설정하고 있지만 롤백이 예외로 인해 충돌하는 이유는 무엇입니까?
해결법
-
==============================
1.내 추측은 ServiceUser.method () 자체가 트랜잭션 적이라는 것이다. 그것은해서는 안됩니다. 이유는 다음과 같습니다.
내 추측은 ServiceUser.method () 자체가 트랜잭션 적이라는 것이다. 그것은해서는 안됩니다. 이유는 다음과 같습니다.
ServiceUser.method () 메소드를 호출 할 때 일어나는 일은 다음과 같습니다.
이제 ServiceUser.method ()가 트랜잭션이 아니라면 다음과 같이됩니다.
-
==============================
2.이 예외는 @Transactional로 표시된 중첩 된 메소드 / 서비스를 호출 할 때 발생합니다. JB Nizet은 메커니즘에 대해 자세히 설명했다. 시나리오를 피하고 그것을 피할 수있는 몇 가지 방법을 추가 할 때 몇 가지 시나리오를 추가하고 싶습니다.
이 예외는 @Transactional로 표시된 중첩 된 메소드 / 서비스를 호출 할 때 발생합니다. JB Nizet은 메커니즘에 대해 자세히 설명했다. 시나리오를 피하고 그것을 피할 수있는 몇 가지 방법을 추가 할 때 몇 가지 시나리오를 추가하고 싶습니다.
Service1과 Service2라는 두 개의 Spring 서비스가 있다고 가정합니다. 우리 프로그램에서 우리는 Service2.method2 ()를 호출하는 Service1.method1 ()을 호출합니다.
class Service1 { @Transactional public void method1() { try { ... service2.method2(); ... } catch (Exception e) { ... } } } class Service2 { @Transactional public void method2() { ... throw new SomeException(); ... } }
별도로 명시하지 않는 한 SomeException은 선택 취소됩니다 (RuntimeException을 확장).
시나리오 :
이 요지에서 테스트 된 모든 시나리오를보십시오.
-
==============================
3.롤백 플래그가 설정되는 원래 예외를 추적하도록 디버거를 설정할 수없는 (또는 원하지 않는) 사용자는 코드 전체에 일련의 디버그 문을 추가하여 줄을 찾을 수 있습니다 롤백 전용 플래그를 트리거하는 코드
롤백 플래그가 설정되는 원래 예외를 추적하도록 디버거를 설정할 수없는 (또는 원하지 않는) 사용자는 코드 전체에 일련의 디버그 문을 추가하여 줄을 찾을 수 있습니다 롤백 전용 플래그를 트리거하는 코드
logger.debug("Is rollbackOnly: " + TransactionAspectSupport.currentTransactionStatus().isRollbackOnly());
코드 전반에 걸쳐이를 추가하면 디버그 문에 번호를 매기고 위의 메소드가 "거짓"에서 "참"으로 돌아가는 것을 확인하여 근본 원인을 좁힐 수있었습니다.
-
==============================
4.@Yaroslav Stavnichiy가 설명했듯이 서비스가 트랜잭션 스프링으로 표시되어 트랜잭션 자체를 처리하려고 시도하는 경우. 예외가 발생하면 롤백 작업이 수행됩니다. 시나리오에서 ServiceUser.method ()가 트랜잭션 작업을 수행하지 않으면 @ Transactional.TxType 주석을 사용할 수 있습니다. 'NEVER'옵션은 트랜잭션 컨텍스트 외부에서 해당 메서드를 관리하는 데 사용됩니다.
@Yaroslav Stavnichiy가 설명했듯이 서비스가 트랜잭션 스프링으로 표시되어 트랜잭션 자체를 처리하려고 시도하는 경우. 예외가 발생하면 롤백 작업이 수행됩니다. 시나리오에서 ServiceUser.method ()가 트랜잭션 작업을 수행하지 않으면 @ Transactional.TxType 주석을 사용할 수 있습니다. 'NEVER'옵션은 트랜잭션 컨텍스트 외부에서 해당 메서드를 관리하는 데 사용됩니다.
Transactional.TxType 참조 문서가 여기에 있습니다.
-
==============================
5.하위 객체를 먼저 저장 한 후 최종 저장소 저장 메소드를 호출합니다.
하위 객체를 먼저 저장 한 후 최종 저장소 저장 메소드를 호출합니다.
@PostMapping("/save") public String save(@ModelAttribute("shortcode") @Valid Shortcode shortcode, BindingResult result) { Shortcode existingShortcode = shortcodeService.findByShortcode(shortcode.getShortcode()); if (existingShortcode != null) { result.rejectValue(shortcode.getShortcode(), "This shortode is already created."); } if (result.hasErrors()) { return "redirect:/shortcode/create"; } **shortcode.setUser(userService.findByUsername(shortcode.getUser().getUsername()));** shortcodeService.save(shortcode); return "redirect:/shortcode/create?success"; }
from https://stackoverflow.com/questions/25322658/could-not-commit-jpa-transaction-transaction-marked-as-rollbackonly by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 스프링 자바 설정에서 @Bean 어노테이션으로 된 메소드 호출하기 (0) | 2018.12.30 |
---|---|
[SPRING] Spring MVC REST 컨트롤러에서 HTTP 헤더 정보에 액세스하는 방법은 무엇입니까? (0) | 2018.12.30 |
[SPRING] 하나의 Spring 애플리케이션에서 web.xml에 여러 서블릿을 등록하는 방법 (0) | 2018.12.29 |
[SPRING] Spring Data JPA는 메소드 이름 해석을 사용하여 엔티티를 셀 수있는 방법이 있습니까? (0) | 2018.12.29 |
[SPRING] Spring은 실제로 어떻게 부트 스트랩을합니까? (0) | 2018.12.29 |