【问题标题】:Spring JPA atomic get or create methodSpring JPA 原子获取或创建方法
【发布时间】:2020-07-20 07:58:31
【问题描述】:

我正在使用 Spring Boot 和 JPA(使用 Hibernate)。

我有一个方法(进入我的服务):

  • 检查数据库中是否已经存在特定实体(例如 I 需要检查是否已经有用户。为此,我使用自定义 JPQL 查询我的 JPA 存储库。
  • 在此之后,如果上一步没有任何结果,我将在数据库中创建条目(使用保存 JPA 存储库方法)同时我还需要创建一个其他实体(对于例如一些与用户相关的信息存储到一个单独的表中)。 因此,在这种情况下,我将有两个 create-query(一个用于 User 表,一个用于 Info-User 表)。
  • 如果步骤 1 已经有一些结果,我显然需要跳过插入步骤。

显然,我需要保证这个方法的原子性

我必须避免可能在数据库中创建重复条目的单独事务。

附加说明:在用户表上,我无法添加一些唯一约束,因为对此有一些不同的组合(例如,如果状态为某个值或类似的值,我可以再次创建相同的用户) .

我尝试在我的方法中仅使用 @Transactional 注释,但我注意到这还不够(使用一些压力测试,我可以在数据库中创建多行)。

所以现在我很困惑。

拥有原子方法的最佳实践是什么? 我需要更改Transaction Isolation level 吗?我需要使用一些Locks吗?

我不是 Spring 专家,但我认为这是一个常见问题,但我无法理解正确的方法。

基本上我正在寻找使用 JPA(和 JPA 存储库)的原子 GET_OR_CREATE 方法

【问题讨论】:

    标签: java spring hibernate jpa spring-transactions


    【解决方案1】:

    在这种情况下,您需要将事务隔离级别设置为SERIALIZABLE,这样只有一个事务可以访问数据库。这可以使用Transactional 注释的isolation 属性来完成:

    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void yourMethod(){
        // ...
    }
    

    在此处阅读有关该主题的更多信息:https://www.baeldung.com/spring-transactional-propagation-isolation

    【讨论】:

    • 感谢您的建议。在我读到的文章中:“它可以防止所有提到的并发副作用,但可以导致最低的并发访问率,因为它按顺序执行并发调用。”所以,我可能会反对这个性能问题。我的情况是否正常?从您的角度来看,它是唯一的解决方案吗?谢谢
    • 并发性和数据完整性始终是一个不能同时兼顾的权衡。也许你必须检查你的要求。并且可以使用唯一约束来防止重复条目。
    • @SimonMartinelli 这意味着如果我有一个唯一的键,我可以使用默认的事务隔离级别?
    • @SimonMartinelli 你确定隔离级别会保证原子性吗?据我了解,两个读取可能同时发生。两者都会看到还没有用户条目。然后第二次写入可能发生在第一个事务完成后。我读到一些 DBMS 使用快照。 IE。第二个事务甚至可以以相同的空结果再次重复读取,尽管第一个事务已经写入了一个条目,因为它是从快照中读取的。但这并不意味着它不能在那之后执行 INSERT。
    • “原子性”在我上面的评论中是错误的术语。它确实是原子的,但作者的问题仍然如我评论中所述。仍然可能有两个 INSERT(如果没有唯一键),其中只有一个。
    猜你喜欢
    • 2015-05-29
    • 2020-08-06
    • 1970-01-01
    • 2018-05-11
    • 1970-01-01
    • 1970-01-01
    • 2015-06-03
    • 2019-01-13
    相关资源
    最近更新 更多