복붙노트

[SPRING] Hibernate JPA를 사용한 작업 단위 처리 문제

SPRING

Hibernate 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. ==============================

    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; 
      }
    }
    
  2. from https://stackoverflow.com/questions/54343137/problem-in-handling-unit-of-work-using-hibernate-jpa by cc-by-sa and MIT license