有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Spring数据JPA何时实际调用数据库上的INSERT?

使用JPARepository/Hibernate保存对象时,它首先检查数据库中是否存在(使用主键),然后插入。因此,我们看到两个日志:SELECT&;插入

这就是我试图通过spring数据所做的:(X和XY是两个不同的对象)

Call Save on XRepository for Object X1

Call Save on XYRepository for Object X1Y1
Call Save on XYRepository for Object X1Y2
Call Save on XYRepository for Object X1Y3

Call Save on XRepository for Object X2

Call Save on XYRepository for Object X2Y1
Call Save on XYRepository for Object X2Y2
Call Save on XYRepository for Object X2Y3

这是我在日志中的观察结果:

SELECT X1
INSERT X1
SELECT X1Y1
SELECT X1Y2
SELECT X1Y3
INSERT X1Y1
INSERT X1Y2
INSERT X1Y3
SELECT X2
INSERT X2
SELECT X2Y1
SELECT X2Y2
SELECT X2Y3
INSERT X2Y1
INSERT X2Y2
INSERT X2Y3

那么Spring数据何时真正调用insert呢?这是怎么回事

这是我所期望的:

SELECT X1
INSERT X1
SELECT X1Y1
INSERT X1Y1
SELECT X1Y2
INSERT X1Y2
SELECT X1Y3
INSERT X1Y3
...

共 (2) 个答案

  1. # 1 楼答案

    SpringDataJPA本身并不直接控制与数据库的交互。它所做的只是与EntityManager交互,因此所有行为效应都由JPA和底层OR映射器定义

    持久性提供程序通常尝试批量处理数据库交互,因为这样可以最大限度地减少开销,特别是在单个会话中执行大量持久性操作时。因此,通常EntityManager仅在以下情况之一发生时才会刷新对磁盘的更改:

    JPA如何处理这个问题

    1. EntityManager(读:Hibernate案例中的Session)被关闭,脏检查机制发现挂起的更改。因此,您可能已经更改了附加实体的属性,或者使用….persist(…)将其添加到持久性上下文中
    2. 要持久化的实体使用ID生成机制
    3. 您可以手动调用flush方法
    4. 您触发一个查询,EntityManager具有挂起的更改。然后,它会将这些数据刷新到数据库中,以确保查询可能已经看到更改的数据

    As an aside: the last point sometimes results in the weird effect of DataIntegrityViolationExceptions being thrown when a query is executed and a lot of people don't get that in the first place. But it's the flushing of pending changes right before the query execution that causes the issue.

    这导致了一些重要的观察结果:

    Spring数据细节

    1. 对于非ID自动生成的实体,不要期望它们在EntityManager关闭之前出现在数据库中使用Spring,这通常绑定到事务的生命周期,因此您可能需要首先提交并检查已更改对象上已更改的属性
    2. 您可以查询对象并检查返回的对象,而不是直接检查对象这使用了我在上面4中描述的内容。注意:对于这种方法,不要使用findOne(…),因为这将使用EntityManager.find(type, id)-方法,该方法通常大量使用一级缓存(可能不首先刷新)
    3. 作为最后一种手段,您可以在JpaRepository接口上使用saveAndFlush(…),但我们强烈建议不要这样做,因为您可以有效地向客户端公开持久层内部。更喜欢使用自动ID生成的实体
  2. # 2 楼答案

    默认情况下,Hibernate在刷新期间插入保存的实体。它解释了为什么XY会批量插入(在刷新期间),以及为什么saveAndFlush()会立即插入它们

    但在插入过程中数据库生成主键的实体(即生成主键,生成策略需要实际插入才能生成密钥)会立即插入,因为Hibernate应该知道已保存实体的ID。这就是你观察到的X