首页 > 解决方案 > 使用 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)
}

当所有订单和客户数据库流程都正常时,需要提交。

  1. 插入订单

    1.a 如果重复订单不回滚。但是,如果 req 中的订单状态与 db 中的订单状态不同,则从表中选择该订单并更新

    1.b 如果在插入 ORDER 过程中出现任何其他错误,则回滚

    1.c 如果没有错误,则继续插入特定客户的订单

  2. 完成特定客户的订单后,更新客户表

  3. 循环继续..

  4. 在处理点 1、2 和 3 时,如果一切正常,则需要提交。如果中间有任何问题,那么所有事务都会回滚

Controller --> Facade 层 --> Service --> Repository/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(); 
}

问题:

当我向一个有单个订单的客户发送请求时,订单重复,我看到 PersistException 在 Service 方法中被捕获,当它从 Service 方法中存在时,它也会抛出 TransactionSystemException(嵌套异常是 RollbackException:事务被标记为仅回滚,无法提交 JPA 事务)被抛出到外观层,而不管我如何抑制内部事务中的异常。

如果我能以这种方式实现工作单元提交或回滚,请提出建议。

预期的:

我希望 Spring 的 @Transactional 通过不回滚并且不影响下一个事务来忽略重复键异常。

标签: springhibernatejpaspring-transactionstransactional

解决方案


您的外部事务仍然失败,因为您将其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; 
  }
}

推荐阅读