【问题标题】:Spring Data: JPA and Nested TransactionSpring Data:JPA 和嵌套事务
【发布时间】:2019-07-12 00:50:41
【问题描述】:

我遇到了 Spring JPA Data 和嵌套事务的问题。以下是我的服务的嵌套事务的两种方法。

@Service
public UserService {

    @Transactional
    public User createUser(UserDto userDto) {
        ....
        user = saveUser(user);
        sendEmail(user);
        ....
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public User saveUser(User user) {
        return userRepository.save(user);
    }

碰巧有一种情况,方法 userRepository.save() 应该抛出异常,但不知何故没有被抛出,看起来它正在等待父事务完成。我原以为 saveUser 方法会引发异常,而 sendEmail 方法甚至不会被执行。

因为UserService.saveUser 方法将传播设置为Propagation.REQUIRES_NEW,所以我希望提交该事务(要执行的 SQL 语句)并且传播任何异常。

我没有设置任何与事务相关的东西,所以我认为刷新模式设置为自动。

谁能发现我做错了什么或我的误解是什么?

【问题讨论】:

  • 为什么你认为 userRepository.save() 应该抛出异常?如果它被抛出 saveUser 事务将被回滚。
  • 在我的特定场景中,因为某些约束失败。所以我期望立即抛出一个异常并且 sendEmail 甚至没有被调用。然而,仅当 createUser 完成时才会引发 saveUser 异常。下面的方法解决了这个问题。非常感谢西蒙

标签: java spring jpa kotlin spring-data-jpa


【解决方案1】:

这是因为您在同一个 bean 中调用 @Transactional 方法。

@Transactional 仅适用于在 spring 创建的代理上调用的方法。这意味着,当您创建 @Service 或其他 bean 时,从外部调用的方法将是事务性的。如果从 bean 内部调用,则不会发生任何事情,因为它不通过代理对象。

最简单的解决方案是将方法移动到另一个@Service 或bean。如果你真的想把它保存在同一个组件中,那么你需要调用它,以便它被spring AOP包裹在代理中。你可以这样做:

private YourClass self;

@Autowired
private ApplicationContext applicationContext;

@PostConstruct
public void postContruct(){
    self = applicationContext.getBean(YourClass.class);
}

然后在self 上调用方法将导致打开一个事务。

换句话说:您没有遇到任何这些异常,因为@Transactional 超过saveUser 不起作用。

【讨论】:

  • 非常感谢。您的建议非常有效。
  • 没问题,很高兴为您提供帮助:)
猜你喜欢
  • 2016-09-10
  • 2012-10-20
  • 2021-11-17
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多