Spring @Transactional issue/challenge 放置在服务层

Spring @Transactional issue/challenge while placing in service layer

我的 Spring 应用程序分层为 Bean、服务和 DAO。所有的@Transactional 注解都在服务层。

这是一个特定场景下的伪代码。

UserBean.java

saveUser() {
    userService.manageUser();
}

UserServiceImpl.java

@Transactional
public void manageUser() {
    userDAO.createUser();
    userDAO.updateParentUser();
}

UserDAOImpl.java

createUser() {
    //insert user record in database
}

updateParentUser() {
    //update parent user's database record
}

在我的保存用户测试用例中,更新父用户操作在某些情况下可能会由于主键冲突而失败,这在意料之中。

由于@Transactional注解是在服务class中实现的,这种违规异常只会在beanclass中被通知。

在我的服务中获取此 PK 违规通知的选项是什么 class? [然后我可以在不同的业务流程中从那里处理它。]

如果我在服务 class 中添加新方法并从那里调用 manageUser(),@Transactional 注释将无法正常工作。这是由于 limitation/property of AOP。 Spring 需要外部调用 @Transactional 方法。

  1. 使用程序化事务管理并在 try catch 块中处理异常
  2. 引入委托class并在那里的事务中执行manageUser:

    @Transactional(REQUIRED)
    public void manageUser() {
        try{
           delegate.manageUser();
        } catch (Exception ex ) {
        //handle
        }
    }
    

    并在委托中 class

    @Transactional(REQUIRES_NEW)
    public void manageUser() {
    }
    

在您从@Transactional 方法return 之前,create/update 不会被提交。如果 create/update 在此之前被刷新到数据库,那么您 可能 在方法中得到异常,但在您的情况下,它在提交之前不会被刷新。

您可以在提交前强制刷新 create/update。您没有说您使用的是 Hibernate 还是 JPA,但是 session.flush()entityManager.flush() 应该可以解决问题。

我转向了 AspectJ 方法,而不是 Spring 基于代理的 AOP。这使我可以灵活地从同一服务的另一个方法调用 manageUser() 方法 class,我可以在那里处理异常。