Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
717 views
in Technique[技术] by (71.8m points)

spring - Problem in Handling Unit of work using Hibernate JPA

I use Spring + Hibernate + JPA

I need to handle the list of customers by inserting their orders.

Here is the Unit of work :

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 is required when all the orders and customer db processes are ok.

  1. Insert order

    1.a If duplicate order do not roll back. But select that order from table and update if the status of the order is different in the req compared to the one in db

    1.b If any other error during inserting of ORDER then roll back

    1.c If no error then proceed inserting orders of the particular Customer

  2. Once orders of the particular Customer is done, then update Customer table

  3. Loop continues..

  4. While handling point 1, 2 and 3 If everything is ok, then commit is required. If any issues in the middle then all transactions are rolled back

Controller --> Facade layer --> Service --> Repository/Dao

Facade:

@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);
     }
}

Service:

@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
  }
}

Repository:

@PersistentContext(unitNmae = "MY_SHCEMA")
EntityManager entityManager;

@Override
public void insertOrderDao(Order order) {
     entityManager.persist(order);
     entityManager.flush(); 
}

Problem:

When I send req with One customer who has single order, where the order is duplicate, I see PersistException is caught inside Service method and when it exists from Service method it also throws TransactionSystemException(nested exception is RollbackException: Transaction is marked as rollback only, could not commit JPA transaction) is thrown to Facade layer irrespective of the how I suppress the exception in inner transaction.

Kindly advice If I can achieve Unit of work commit or rollback in this way.

Expected:

I want Spring's @Transactional to ignore Duplicate key exceptions by not rolling back and not affecting the next transaction.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your outer transaction still fail because you throw ApplicationDuplOrderException() inside your service.

You should setup your services like below:

@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; 
  }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...