使用JPARepository / Hibernate保存对象时,它首先检查数据库中是否存在(使用主键),然后检查插入.所以我们看到2个日志:SELECT插入.这就是我想通过弹簧数据做的事情:( X和XY是2个不同的对象)Call Save on XReposito...
使用JPARepository / Hibernate保存对象时,它首先检查数据库中是否存在(使用主键),然后检查插入.所以我们看到2个日志:SELECT&插入.
这就是我想通过弹簧数据做的事情:( X和XY是2个不同的对象)
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 Data什么时候实际调用插入?这是如何运作的?
这是我的预期:
SELECT X1
INSERT X1
SELECT X1Y1
INSERT X1Y1
SELECT X1Y2
INSERT X1Y2
SELECT X1Y3
INSERT X1Y3
...
解决方法:
Spring Data JPA本身不直接控制与数据库的交互.它所做的就是与EntityManager进行交互,因此所有行为效果都由JPA和底层OR映射器定义.
持久性提供程序通常会尝试批量处理数据库交互,因为这可以最大限度地减少开销,特别是如果您在单个会话中执行大量持久性操作.因此,如果出现以下某种情况,EntityManager通常只会将更改刷新到磁盘:
JPA如何处理这个问题
> EntityManager(读取:Hibernate案例中的Session)关闭,脏检查机制找到挂起的更改.因此,您可能已使用… .persist(…)更改了附加实体的属性或将其添加到持久性上下文中.
>要持久化的实体使用ID生成机制.
>您手动调用flush方法.
>您触发查询并且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 Data的具体细节
>对于非ID自动生成的实体,不要指望它们在EntityManager关闭之前出现在数据库中.对于Spring,这通常绑定到事务的生命周期,因此您可能需要先提交并检查已更改对象的已更改属性.
>您可以查询并检查返回的对象,而不是直接检查对象.这使用我在上面4中描述的内容.注意:不要对此方法使用findOne(…),因为这将使用EntityManager.find(type,id)-method,它通常大量使用第一级缓存(可能没有先刷新).
>作为最后的手段,您可以在JpaRepository接口上使用saveAndFlush(…),但我们强烈建议您不要这样做,因为您有效地向客户端公开了持久层内部.首选使用自动ID生成的实体.
本文标题为:java – Spring Data JPA何时实际上在数据库上调用INSERT?
基础教程推荐
- 详解velocity模板使javaWeb的html+js实现模块化 2023-08-01
- Java异常分类处理抛出捕获操作详解 2023-05-24
- Java模拟实现扑克牌洗牌和发牌的示例代码 2023-05-25
- Java中初始化List集合的八种方式汇总 2023-01-18
- jsp给后台带多个参数的方法 2023-08-01
- Java利用栈实现简易计算器功能 2022-11-12
- 微信小程序微信登录的实现方法详解(JAVA后台) 2023-03-07
- Go&java算法之最大数示例详解 2023-04-16
- MyBatis批量插入几千条数据为何慎用foreach 2023-06-30
- 深入了解集合操作工具Guava Collect 2023-06-10