【问题标题】:Spring Data Rest transaction boundariesSpring Data Rest 事务边界
【发布时间】:2016-06-05 22:45:52
【问题描述】:

我一直在使用存储库验证器通过 Spring Data Rest 和 JPA 存储库实现一些业务逻辑/验证,如下所述:

http://docs.spring.io/spring-data/rest/docs/current/reference/html/#events.

在深入研究 SDR 代码后,我注意到验证器(或更一般地说,存储库侦听器)并未在事务中调用。

来自org.springframework.data.rest.webmvc.RepositoryEntityController的源码:

private ResponseEntity<ResourceSupport> createAndReturn(Object domainObject, RepositoryInvoker invoker,
            PersistentEntityResourceAssembler assembler, boolean returnBody) {
        // validation logic is implemented in the listener, no transaction yet
        publisher.publishEvent(new BeforeCreateEvent(domainObject));
        // invoker calls repository, which is wrapped in the transactional proxy, 
        // only then transaction begins
        Object savedObject = invoker.invokeSave(domainObject);
        publisher.publishEvent(new AfterCreateEvent(savedObject));

        PersistentEntityResource resource = returnBody ? assembler.toFullResource(savedObject) : null;

        HttpHeaders headers = prepareHeaders(resource);
        addLocationHeader(headers, assembler, savedObject);

        return ControllerUtils.toResponseEntity(HttpStatus.CREATED, headers, resource);
}

从代码中可以看出,侦听器不会在事务中调用,这可能会导致最终的数据一致性问题。

我错过了什么吗?还是框架只是错误地设置了事务边界?

【问题讨论】:

  • 我认为它是这样设计的。 'Before' 事件应该在保存之前发送,并且无论保存是否成功都应该成功。这是 spring 的通用方法,SDR 仅遵循它。在我看来,无法为存储库操作附加额外的逻辑使得整个概念几乎无法使用。所以我们必须在 80% 的情况下使用自定义控制器。
  • 好吧,我不太肯定“之前”事件独立于实际的保存调用。在 SDR documentation 中,建议使用验证器作为事件监听器,因此实际的存储库调用取决于验证是否成功。无论如何,我知道底层 Spring Data 实现可能不一定是 JPA,但是在文档中说明关于事务的简单说明确实很好:)
  • 如果您的事件监听器需要参与更大的事务,那么您很可能不需要事件监听器,而是需要一个成熟的服务。文档明确指出 Spring Data REST 只是公开存储库。

标签: java spring transactions spring-data-jpa spring-data-rest


【解决方案1】:

在 Spring Data Rest 中,存储库方法将运行自己的事务。我也认为这在某些情况下是有问题的。至少事件处理程序应该与存储库方法在同一个事务中运行。

这里有一个类似的问题: Handle spring-data-rest application events within the transaction

特别是这个答案提供了一种解决方法,允许您将整个 RepositoryEntityController 方法包装在事务中 - 我认为这是您大部分时间需要的:

https://stackoverflow.com/a/30713264/5371736

【讨论】:

  • 感谢您的提示!最后,我们的逻辑非常简单,所以我们决定让验证器是非事务性的,因为简单的乐观锁定就足够了。然而,在单个有问题的用例中,涉及多个实体的锁定和更新,我们决定使用自定义控制器调用良好的旧事务服务。
  • “至少事件处理程序应该和存储库方法在同一个事务中运行” 为什么?
  • 我认为在你的活动中做一些额外的数据库访问是一个常见的要求——例如做一些审计。当审核失败时,您将很容易达到希望回滚更新的地步。我们经常在更新或创建后使用 spring-amqp 进行消息传递 - 如果发送消息失败,我们还希望回滚事务,反之亦然。
猜你喜欢
  • 1970-01-01
  • 2017-05-22
  • 1970-01-01
  • 2016-09-10
  • 2020-07-30
  • 1970-01-01
  • 2015-01-01
  • 2019-07-05
  • 2016-10-26
相关资源
最近更新 更多