Spring Boot 如何在同一事务中的flush()之后获取更新的对象(Hibernate/ Sping Boot )

bihw5rsg  于 2023-01-13  发布在  Spring
关注(0)|答案(1)|浏览(229)

我有一个约10000个对象的列表。
我正在尝试调用一个***mysql更新查询(过程)***,然后在同一个事务中获取更新的对象。这可以实现吗?
当我调用***delete语句+ flush()***时,hib会检索到正确的对象(删除的对象丢失了)。但是当我尝试***update语句+ flush()***时,hib会检索到初始的未更改对象。

@Transactional
void test() {
  //...
  em.createQuery("delete from StorefrontProduct sp where sp in (:storefrontProducts)")
                    .setParameter("storefrontProducts", storefrontProductsToDelete)
                    .executeUpdate();

  // example
  em.createQuery("update StorefrontProduct sp set sp.orderIndex=0 where sp.id=90")
                            .executeUpdate();
  em.flush();

  //Simple JPA query
  List<StorefrontProduct> result = repository.findAllByPreviousOrderIndexIsNotNull();

  //additional code....
}

运行上述代码并在findAll调用后放置断点后,第一个查询中提供的对象被删除并刷新,但更新查询未刷新。

bvuwiixz

bvuwiixz1#

这就是众所周知的Hibernate反直觉行为。
首先,如果刷新模式设置为AUTOem.flush()调用可能是多余的(在这种情况下,Hibernate会在执行更新/删除查询之前自动将persistence context(会话级缓存)与底层数据库同步)。

删除和连续选择案例

  • 您发出delete,然后发出select,因为select不再显示已删除的记录,所以您在结果集中看不到已删除的记录,但是如果您调用findById,则可能会找到已删除的记录。
    更新和后续选择案例
  • 当处理结果集时,您发出update,然后select。Hibernate看到存储在数据库中的记录和存储在persistence context中的记录,并且它假设**persistence context是真实数据的来源**,这就是您看到“陈旧”数据的原因。

有以下选项可以缓解这种违反直觉的行为:
1.不执行直接更新,而是使用“慢”find/save API

  1. detachrefresh在直接更新之后的陈旧实体,em.clear()也可能有帮助,但是它完全清除了persistence context,这可能是不希望的

相关问题