Spring Data问题-派生的删除不起作用

问题描述

我有一个spring boot应用程序(基于spring-boot-starter-data-jpa。我的配置绝对是最低的,只有一个表和一个实体。

我正在使用CrudRepository 和两个都可以使用的findBy方法我有一个派生的deleteBy方法-不起作用。签名很简单:

public interface MyEntityRepository<Long,MyEntity> extends CrudRespository<> {
    Long deleteBySystemId(String systemId);
    // findBy methods left out
}

实体也很简单:

@Entity @Table(name="MyEntityTable")
public class MyEntity {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="MyEntityPID")
    private Long MyEntityPID;

    @Column(name="SystemId")
    private String systemId;

    @Column(name="PersonIdentifier")
    private String personIdentifier;

   // Getters and setters here,also hashCode & equals.
}

deleteBy方法不起作用的原因是因为它似乎只向数据库发出“ select”语句,该语句选择所有具有SystemId和我指定的值的MyEntity行。使用MysqL全局日志,我捕获了实际的物理sql,并在数据库上手动将其发布,并验证了它返回了大量的行。

因此,Spring或更确切地说是Hibernate试图选择必须删除的行,但实际上从不发出DELETE FROM语句。

根据note on Baeldung,这种选择语句是正常的,从某种意义上说,Hibernate将首先选择要删除的所有行,然后为每个行发出delete语句。

有人知道为什么这个派生的deleteBy方法不起作用吗?我的@Configuration上有@TransactionManagementEnabled,方法调用为@Transactional。 MysqL日志显示spring设置了autocommit = 0,因此似乎已正确启用了事务。

我通过手动注释派生的delete方法解决此问题:

public interface MyEntityRepository<Long,MyEntity> extends CrudRespository<> {
    @Modifying
    @Query("DELETE FROM MyEntity m where m.systemId=:systemId")
    Long deleteBySystemId(@Param("systemId") String systemId);
    // findBy methods left out
}

这有效。包括交易。但这不是必须的,我不需要添加查询注释。

Here is a person的问题和我完全一样。但是,Spring开发人员很快就洗手了,并将其记为Hibernate问题,因此没有解决方案或解释。

哦,作为参考,我正在使用Spring Boot 2.2.9。

解决方法

tl; dr

全部在reference documentation中。这就是JPA的工作方式。 (我在洗手。

详细信息

这两种方法有两种不同的作用:Long deleteBySystemId(String systemId);通过给定的约束加载实体并最终发出EntityManager.delete(…),持久性提供者将延迟该延迟,直到事务提交为止。即调用后的代码不能保证更改已同步到数据库。反过来,这是由于JPA允许其实现实际执行此操作。不幸的是,Spring Data无法在此之上解决任何问题。 (更多的摩擦,更多的洗涤,再加上一点肥皂。

reference documentation通过触发EntityManager等生命周期事件来证明这种行为与@PreDelete的行为(同样是JPA抽象,与Spring Data无关)。哪些用户希望被触发。

手动声明修改查询的第二种方法是声明要在数据库中执行查询 ,这意味着实体生命周期不会触发,因为实体不会得到提前实现。

但是,Spring开发人员很快洗手并将其记为Hibernate问题,因此在那里找不到解决方案或解释。

有详细的解释,说明了为什么其工作方式与故障单注释中的工作方式相同。甚至提供解决方案。解决方案和建议,以控制此行为的堆栈部分对此进行介绍。 (水龙头,伸手去拿毛巾。