【问题标题】:@PreUpdate does not work with Spring Data JPA@PreUpdate 不适用于 Spring Data JPA
【发布时间】:2023-03-06 20:50:01
【问题描述】:

我有一个实体:

@Entity
@EntityListeners(MyEntityListener.class)
class MyEntity{ ... }

还有听者:

class MyEntityListener{
    @PrePersist
    @PreUpdate
    public void doSomething(Object entity){ ... }
}

我正在为此实体 (1.4.1) 和 EclipseLink 使用 Spring Data 生成的 DAO。代码行为如下:

MyEntity entity = new Entity();
entity = dao.save(entity); // the doSomething() is called here
// change something it the entity and save it again
dao.save(entity); // the doSomething() is NOT called here, checked with breakpoint

问题已经是described by someone in 2009,但是他们没有想出任何解决方案。我想知道是否有人知道如何解决它?

【问题讨论】:

  • 你确定doSomething() 没有被第二次调用吗?它可以在事务提交之前调用,而不是立即调用。
  • 您是否尝试在第二次 save() 之前分离实体?
  • @AndreiI 你是对的,当我在第二次保存之前通过entity = dao.findOne(entity.getId()) 获取实体时,侦听器的方法被成功调用。如果您知道发生了什么,请将其发布为答案,以及原因。

标签: java spring jpa spring-data-jpa


【解决方案1】:

如你所说,第二次调用回调方法,如果实体被分离或再次从数据库中获取。

我无法准确解释,但可以想到here 描述的场景,即在第二次save() 调用之前没有识别出脏字段,因此没有调用@PreUpdate 回调。或者它可能只是您的 EclipseLink 版本中的一个错误。


更新

在 JPA 2.0 规范中,我发现了以下内容,这正是您的行为(3.5.2 实体的生命周期回调方法的语义):

请注意,PreUpdate 和 PostUpdate 回调发生在实体被持久化并且 随后在单个交易中修改或当实体被修改时 修改并随后在单个事务中删除。 便携式应用程序不应依赖此类行为。

【讨论】:

    【解决方案2】:

    您围绕两个不同的 save() 的事务设置是什么?

    我认为save()/update()/merge()/persist()之间会有一些不同,对于一个实体的不同状态(瞬态,持久,分离),操作和你不一样思想和你的注释@PrePersist 和@PreUpdate 没有生效。

    【讨论】:

    • 我开启了 Spring 的事务管理,但刷新似乎不是问题,因为当我将两个 save 调用替换为 saveAndFlush 时,没有区别。
    • 第一次保存后,实体仍处于持久状态。也许 saveOrUpdate() 可以解决您的问题。
    • saveOrUpdate() 既不在JpaRepository 也不在CrudRepository 接口中。
    • 有没有办法在第二次保存之前分离持久实体?
    • 我不确定此链接是否适用于您的情况stackoverflow.com/questions/13588565/… 是否有方法 EntityManager.detach()?
    猜你喜欢
    • 2015-05-31
    • 1970-01-01
    • 2016-12-03
    • 2019-10-23
    • 2019-08-13
    • 1970-01-01
    • 2018-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多