[SPRING] Hibernate JPA를 사용한 작업 단위 처리 문제
SPRINGHibernate JPA를 사용한 작업 단위 처리 문제
나는 Spring + Hibernate + JPA를 사용한다.
고객의 주문을 삽입하여 고객 목록을 처리해야합니다.
다음은 작업 단위입니다.
for(Customer customer: CustomerList) {
List<Order> orderList = customer.getOrders();
for(Order order: OrderList) {
//1. Insert order into ORDER table
//If insert fails due to Duplicate key then no rollback and I follow steps 2 & 3.
//If insert fails due to any reason except duplicate key then rollback all the previous transactions
//2. select the order record (If any issue during selection then rollbackall the previous transactions)
//3. Update the order If status of the order is different from that in DB (If any issue during update then rollback all the previous transactions)
}
// 4. Update Customer record into CUSTOMER table (If any issue during update then rollback all the previous transactions)
}
Commit은 모든 주문과 고객 DB 프로세스가 정상 일 때 필요합니다.
컨트롤러 -> 외관 레이어 -> 서비스 -> 저장소 / Dao
정면:
@Autowired
MyServiceBean serviceBean;
@Transactional(noRollbackFor = {EntityExistsException.class, PersistException.class, ConstraintViolationException.class, DataIntegrityViolationException.class})
@override
public void facadeMethod(MyReq req) {
List<Customer> custList = req.getCustomers():
for(Customer customer: CustList) {
List<Order> orderList = customer.getOrders();
for(Order order: orderList) {
String dbAction = "";
try {
dbAction = serviceBean.insertOrder(order);
} catch(Exception e) {
// log exception and roll back completely
}
if("handleDupl".equalsTo(dbAction) {
serviceBean.handleDuplOrder(order);
}
}
myService.updateCustomer(customer);
}
}
서비스:
@Autowired
MyRepository repo;
@Transactional(propagation = propagation.REQUIRES_NEW)
@override
public String inserOrder() {
String dbAction = "";
try {
repo.insertOrderDao(order);
} catch(all duplicate key exceptions like entityExist, persist, ConstraintVioaltion, DataIntegrity e) {
dbAction = "handleDuplOrder";
} catch(all other Exception except duplicate key e) {
// roll back and throw exception to Facade layer
}
return dbAction;
}
@Transactional(propagation = propagation.REQUIRES_NEW)
@override
public void handleDuplOrder(Order order) {
try {
repo.selectOrderDao(order);
repo.updateOrder(order);
} catch(Exception e) {
// roll back and throw exception to Facade layer
}
}
저장소:
@PersistentContext(unitNmae = "MY_SHCEMA")
EntityManager entityManager;
@Override
public void insertOrderDao(Order order) {
entityManager.persist(order);
entityManager.flush();
}
문제:
주문이 중복 된 단일 주문을 가진 한 고객과 req를 보낼 때 PersistException이 서비스 메서드 내에서 catch되고 Service 메서드에서 존재할 때 TransactionSystemException을 throw합니다 (중첩 예외는 RollbackException : 트랜잭션이 롤백으로 만 표시됨, JPA 트랜잭션을 커밋 할 수 없음) 내부 트랜잭션의 예외를 어떻게 억제하는지에 관계없이 Facade 계층에 던져진다.
친절하게 조언 만약 내가 이런 식으로 작업 단위 커밋이나 롤백을 달성 할 수 있다면.
예상 :
서비스 트랜잭션이 Requires_New 인 경우 특히 Duplicate 키 예외의 경우 호출하는 메소드의 트랜잭션에는 영향을 미치지 않습니다
해결법
-
==============================
1.서비스 내부에 ApplicationDuplOrderException ()을 던져서 외부 트랜잭션도 계속 실패합니다.
서비스 내부에 ApplicationDuplOrderException ()을 던져서 외부 트랜잭션도 계속 실패합니다.
다음과 같이 서비스를 설정해야합니다.
@Transactional @Override public void facadeMethod(MyReq req) { List<Customer> custList = req.getCustomers(): for(Customer customer: CustList) { List<Order> orderList = customer.getOrders(); for(Order order: orderList) { try { myService.insertOrder(order); } catch(Exception e) { // log exception and roll back completely throw e; // important, you must rethrow } } myService.updateCustomer(customer); } } @Transactional(propagation = propagation.REQUIRES_NEW) @Override public void inserOrder() { try { repo.insertOrderDao(order); } catch(all duplicate key exceptions like entityExist, persist, ConstraintVioaltion, DataIntegrity e) { log.error(xxx); // instead of throwing } catch(all other Exception except duplicate key e) { throw e; } }
from https://stackoverflow.com/questions/54343137/problem-in-handling-unit-of-work-using-hibernate-jpa by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] JsonDeserializer에서의 Autowiring : SpringBeanAutowiringSupport 대 HandlerInstantiator (0) | 2019.01.31 |
---|---|
[SPRING] Spring-Boot : tomcat 커넥터를 추가하여 컨트롤러에 바인딩하는 방법 (0) | 2019.01.31 |
[SPRING] 스프링 부트를 사용하는 동안 스프링 배치 범위 문제 (0) | 2019.01.31 |
[SPRING] 런타임시 스프링 <task : scheduled> 객체는 어떻게 표현됩니까? (0) | 2019.01.31 |
[SPRING] 프로그래밍 방식으로 스프링 부트 응용 프로그램 다시 시작 / 스프링 컨텍스트 새로 고침 (0) | 2019.01.31 |