当前位置: 首页 > 知识库问答 >
问题:

如何阻止spring data JPA在save()之前执行SELECT?

龚跃
2023-03-14

我们正在针对现有数据库编写一个新的应用程序。我正在使用Spring数据JPA,只需做一个

MyRepository.save() 

在我的新实体上,使用

MyRepository extends CrudRepository<MyThing, String>

我在日志中注意到,hibernate在插入之前进行了一次选择,而且这需要很长时间,即使在使用索引时也是如此。

我在这里搜索过这个,我找到的答案通常与冬眠有关。我对JPA很陌生,JPA和Hibernate似乎是紧密结合在一起的,至少在Spring数据环境中使用它时是这样。链接的答案建议使用Hibernate persist(),或者以某种方式使用会话,可能来自entityManager?我不需要直接使用sessions、EntityManager或任何Hibernate API。到目前为止,我已经在我的存储库中使用save()和几个@查询完成了简单的插入。

共有3个答案

太叔昆
2023-03-14

我在存储库中创建了一个自定义方法:

    public void persistAll(Iterable<MyThing> toPersist) {
        toPersist.forEach(thing -> entityManager.persist(thing));
    }
宇文修文
2023-03-14

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

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

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

如果您确实必须插入自己的id,并且希望阻止选择插入,那么请实现持久性,例如。

@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;
    }
}
商佑运
2023-03-14

这是您使用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);
    }
}

它执行以下操作:

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

Spring数据文档链接

因此,如果您的一个实体的ID字段不为null,Spring将让Hibernate进行更新(以及之前的选择)。

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

 类似资料:
  • 我最近在论坛上问了一个问题,为什么ExecutorService在获得期货后阻止了我的程序:ExecutorService和Future阻止了主线程 问题是,经过大量的调试,有罪的线不是未来。get()但是

  • 假设一个线程在条件变量上阻塞: 互斥锁被解锁,尝试锁定互斥锁的其他线程被解锁: 同时还有另一个线程正在等待获取关键部分的所有权: 现在的问题是:调用pthread_cond_signal()时,是否保证pthread_cond_wait()[1]将在pthread_mutex_lock()[2]之前解除阻塞? POSIX规范似乎没有说明这种情况。

  • 我对使用Selenium是新手,在Selenium Grid 2中使用RemoteWebDriver时遇到了一些问题。我想知道我的代码出了什么问题。谢谢 我分3步设置RemoteWebDriver: > 将Chrome驱动程序设置为系统属性,我检查了路径是否正确 设置功能 通过RemoteWebDriver打开驱动程序 结果通过前两步,但在最后一步失败,因为日志没有显示。似乎在设置RemoteWe

  • 问题内容: 我正在尝试结合以下注释: 像下面的代码: @Before方法中的代码在@Sql批注中的脚本“ dml-parametro.sql”之后运行。 这样做对吗? 对于此解决方案,我使用@After而不是@Before,但我想在测试执行之前而不是之后cdelete表。 我不想使用@SqlConfig。我没有在测试级别上使用Transacional范围,因此我需要在每种测试方法中清除表。如果每个

  • 在我的Espresso测试执行和AlertDialog会被提示并等待用户响应。Espresso测试只有在我按下“Accept”按钮但我想测试代替用户执行此事件时才会继续。 我注意到我的线程选项卡上有以下状态

  • 我有一个实体,它是和另一个实体,其中预先存在于数据库中,并且是固定的。 实体: 因为我认为要添加新的,只需要就足够了,不需要其他参数。但是每次运行时,它都会运行语句,在之前选择by的所有字段。 我的问题是:如何删除这个不必要的操作,以便在之前不需要?(我知道可以实现自定义sql语句,但我觉得这样会破坏JPA的面向对象)