【问题标题】:Spring @Transactional issue/challenge while placing in service layer放置在服务层时的Spring @Transactional问题/挑战
【发布时间】:2015-09-20 02:33:50
【问题描述】:

我的 Spring 应用程序被分层为 Bean、Service 和 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注解是在service类中实现的,这个违规异常只会在bean类中通知。

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

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

【问题讨论】:

  • 你说“这个违反异常只会在bean类中通知”是什么意思。当然如果异常是在服务类中抛出的,那么你也可以在服务类中捕获并妥善处理?
  • @ConMan 当@Transactional 方法“退出”时会发生此异常。因此,使用当前代码,我将无法在服务类中捕获它。

标签: spring jakarta-ee spring-transactions transactional


【解决方案1】:

在您从 @Transactional 方法返回之前,不会提交创建/更新。如果在此之前创建/更新已刷新到数据库,那么您可能在方法中得到异常,但在您的情况下,直到提交才会刷新。

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

【讨论】:

  • 你一针见血!!!。我正在使用 JPA,entityManager.flush() 运行良好。现在我能够处理服务类中的异常。谢谢。
【解决方案2】:
  1. 在 try catch 块中使用程序化事务管理和处理异常
  2. 引入一个委托类并在那里的事务中执行manageUser:

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

    在委托类中

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

【讨论】:

  • 感谢您的建议。不幸的是,这些选项可能不适合我的情况。程序化事务管理是最不受欢迎的。我有多个地方都有这种情况,因为为委托层添加一个对我来说不是一个好的建议。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2010-12-22
    • 2015-01-07
    • 2011-04-22
    • 2021-01-15
    • 1970-01-01
    • 2020-06-26
    • 2011-01-05
    • 2021-03-19
    • 1970-01-01
    相关资源
    最近更新 更多