java 如何在 save() 之前阻止 Spring Data JPA 执行 SELECT?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45635827/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 08:48:47  来源:igfitidea点击:

How do I stop spring data JPA from doing a SELECT before a save()?

javaspringhibernatespring-data-jpa

提问by user26270

We are writing a new app against an existing database. I'm using Spring Data JPA, and simply doing a

我们正在针对现有数据库编写新应用程序。我正在使用 Spring Data JPA,并且只是做了一个

MyRepository.save() 

on my new entity, using

在我的新实体上,使用

MyRepository extends CrudRepository<MyThing, String>

I've noticed in the logs that hibernate is doing a Select before the insert, and that they are taking a long time, even when using the indexes.

我在日志中注意到 hibernate 在插入之前执行 Select ,并且它们花费很长时间,即使在使用索引时也是如此。

I've searched for this here, and the answers I've foundusually are related to Hibernate specifically. I'm pretty new to JPA and it seems like JPA and Hibernate are pretty closely intertwined, at least when using it within the context of Spring Data. The linked answers suggest using Hibernate persist(), or somehow using a session, possibly from an entityManager? I haven't had to do anything with sessions or entityManagers, or any Hibernate API directly. So far I've gotten simple inserts done with save() and a couple @Query in my Repositories.

我在这里搜索过这个,我找到答案通常与 Hibernate 相关。我对 JPA 很陌生,而且 JPA 和 Hibernate 似乎非常紧密地交织在一起,至少在 Spring Data 的上下文中使用它时。链接的答案建议使用 Hibernate persist(),或者以某种方式使用会话,可能来自 entityManager?我不必直接对会话或实体管理器或任何 Hibernate API 做任何事情。到目前为止,我已经在我的存储库中使用 save() 和几个 @Query 完成了简单的插入。

回答by Bertrand88

Here is the code of Spring SimpleJpaRepository you are using by using Spring Data repository:

这是您使用 Spring Data 存储库使用的 Spring SimpleJpaRepository 的代码:

@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

It does the following:

它执行以下操作:

By default Spring Data JPA inspects the identifier property of the given entity. If the identifier property is null, then the entity will be assumed as new, otherwise as not new.

默认情况下,Spring Data JPA 检查给定实体的标识符属性。如果标识符属性为空,则实体将被假定为新的,否则为不是新的。

Link to Spring Data documentation

链接到 Spring Data 文档

And so if one of your entity has an ID field not null, Spring will make Hibernate do an update (and so a SELECT before).

因此,如果您的实体之一的 ID 字段不为空,Spring 将使 Hibernate 进行更新(以及之前的 SELECT)。

You can override this behavior by the 2 ways listed in the same documentation. An easy way is to make your Entity implements Persistable (instead of Serializable), which will make you implement the method "isNew".

您可以通过同一文档中列出的 2 种方式覆盖此行为。一个简单的方法是让您的实体实现 Persistable(而不是 Serializable),这将使您实现方法“isNew”。

回答by Paul Hilliar

If you provide your own id value then Spring Data will assume that you need to check the DB for a duplicate key (hence the select+insert).

如果您提供自己的 id 值,那么 Spring Data 将假设您需要检查数据库中的重复键(因此选择+插入)。

Better practice is to use an id generator, like this:

更好的做法是使用 id 生成器,如下所示:

@Entity
public class MyThing {
    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "uuid2")
    private UUID id;
}

If you really must insert your own id and want to prevent the select+insert then implement Persistable, e.g.

如果你真的必须插入你自己的 id 并且想要阻止 select+insert 然后实现 Persistable,例如

@Entity
public class MyThing implements Persistable<UUID> {

    @Id
    private UUID id;

    @Override
    public UUID getId() {
        return id;
    }

    //prevent Spring Data doing a select-before-insert - this particular entity is never updated
    @Override
    public boolean isNew() {
        return true;
    }
}