Spring boot Spring数据问题-派生的删除不起作用

Spring boot Spring数据问题-派生的删除不起作用,spring-boot,hibernate,spring-data-jpa,spring-data,Spring Boot,Hibernate,Spring Data Jpa,Spring Data,我有一个基于springbootstarter数据jpa的springboot应用程序。我有一个绝对最小的配置正在进行,只有一个表和实体 我正在使用Crudepository和一些findBy方法,这些方法都有效。我有一个派生的deleteBy方法,它不起作用。签名很简单: public interface MyEntityRepository<Long, MyEntity> extends CrudRespository<> { Long deleteBySys

我有一个基于springbootstarter数据jpa的springboot应用程序。我有一个绝对最小的配置正在进行,只有一个表和实体

我正在使用Crudepository和一些findBy方法,这些方法都有效。我有一个派生的deleteBy方法,它不起作用。签名很简单:

public interface MyEntityRepository<Long, MyEntity> extends CrudRespository<> {
    Long deleteBySystemId(String systemId);
    // findBy methods left out
}
deleteBy方法不起作用的原因是它似乎只向数据库发出select语句,该语句选择所有具有SystemId和我指定的值的MyEntity行。使用mysql全局日志,我捕获了实际的物理sql,并在数据库上手动发布它,并验证它是否返回了大量行

所以Spring,或者更确切地说Hibernate,试图选择它必须删除的行,但它实际上从未发出delete FROM语句

根据一个示例,此select语句是正常的,即Hibernate将首先选择它要删除的所有行,然后为每个行发出delete语句

有人知道为什么这个派生的deleteBy方法不起作用吗?我在@Configuration上启用了@TransactionManagement,并且调用的方法是@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
}
这很有效。包括交易。但这不应该是,我不需要添加那个查询注释

他和我有完全相同的问题。然而,Spring开发人员很快就洗手不干了,并将其视为Hibernate问题,因此没有找到解决方案或解释

哦,作为参考,我使用的是Spring Boot 2.2.9。

tl;博士 一切都在计划之中。这就是JPA的工作方式。我搓手洗手

细节 这两种方法做了两件不同的事情:LongDeleteBySystemItemString systemId;根据给定的约束加载实体,并最终发出EntityManager.delete…持久性提供程序将延迟到事务提交。即,调用后的代码不能保证更改已同步到数据库。这反过来又是由于JPA允许其实现实际做到这一点。不幸的是,Spring数据无法解决这个问题。多擦,多洗,再加一点肥皂

通过对EntityManager的需求再次证明了这种行为是JPA抽象的,而不是Spring数据触发用户期望触发的@predelet等生命周期事件

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

然而,Spring开发人员很快就洗手不干了,并将其视为Hibernate问题,因此没有找到解决方案或解释


在罚单的注释中有详细的解释,解释了为什么它是这样工作的。甚至还提供了一些解决方案。解决方法和建议,以便在堆栈中控制此行为的部分使用此方法。关上水龙头,伸手拿毛巾。

在Long DeleteBySystemString systemId上添加@Transactional;您应该为您的存储库创建带有@Transactional和@Service注释的服务。@DirkDayne是的,但它不是。同样的结果。另外,我不希望我的存储库管理我的事务,我在使用存储库的服务方法的其他地方有事务注释。此外,无论事务如何,都应该向数据库发出某种DELETE语句。没有。@Seldo97我有这些。这没什么区别。没有发出DELETE语句,只有SELECT语句我很高兴您的手现在干净整洁:-我知道这不是Springs本身的错误,而是底层JPA实现。但这种工作方式最终会给开发人员带来更多的麻烦,而不是更少。你给出的理由在我看来像是武断的技术细节。哦,预告片一定会开火。那就开枪吧,有什么大不了的?为什么它会延迟删除而不是插入?JPA在删除之前尝试插入时,会反转事务中数据库操作的顺序。这究竟有何道理呢?这方面的用例在哪里?这些都是很好的问题。Hibernate团队。同样:我们控制实现所有这些的代码。
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
}