Spring Data JPA + Hibernate : catch block inside a Transactional method is never reached

走远了吗. 提交于 2019-12-23 05:57:07

问题


In our Spring Data JPA + Hibernate application, there are various methods having multiple JPA operations inside the same transaction - below is the code/configuration on one of the spring service methods.

@Transactional(rollbackFor=MyAppException.class)
public void updateCustomerprofile(String customerKey) throws MyAppException{
    try{
    CustomerId customerIdObj = customerIdRepository.findOne(customerKey);
    customerIdObj.setCreatedUser("<loggedin-user>");
     // more logic here
    customerIdObj = customerIdRepository.save(customerIdObj);
    }catch(DataAccessException dae){
        //this catch block is never reached even if there is an exception while saving because of JPA flusheing at the end of transaction
        throw new MyAppException(dae);
    }

}

It's been observed that the execution will never reach the catch block even if there is an exception thrown while saving the record - and it is because JPA flushes at the end of the transaction.

Where exactly should this catch block be placed?

Should we be catching DataAcccessException on the web layer (bean)?

If so, are we not taking the datalayer dependencies on to web layer?

If I have to wrap DataAccessException into my application specific exception, how do I do it?

Please suggest.


回答1:


The problem here is that the exception is not thrown within your code, but when the container commits the transaction (see also this answer). To avoid using bean-managed transactions, you can:

  • Synchronize the persistence context via EntityManager.flush(),
  • Use an EJB interceptor with the @AroundInvoke annotation which begins, commits and rollbacks the transaction (similar approach to BMT), or
  • Wrap the code which is supposed to throw the exception in a method with @TransactionAttribute(REQUIRES_NEW).

See also this thread, where some details about the REQUIRES_NEW approach are further explained.




回答2:


add a entityManager.flush() inside the catch block, or move the catch block around the @Transactional annotated method.

The reason is that often the entity manager is free to decide when it write the data into the database (that is the point when the exception occurs). Typically the writing to the database is done

  • before a "Select" query,
  • when explicit invoke entityManager.flush() or
  • when submitting a transaction.

So the solution is: that you make sure that the entity manager writes the (illegal) data to the database within your try-block.



来源:https://stackoverflow.com/questions/24736954/spring-data-jpa-hibernate-catch-block-inside-a-transactional-method-is-never

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!