【发布时间】:2020-12-06 16:29:13
【问题描述】:
我有一个 spring boot 应用程序(基于 spring-boot-starter-data-jpa。我有一个绝对最少的配置,只有一个表和实体。
我正在使用 CrudRepository
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”语句,该语句选择所有 MyEntity 行,其中 SystemId 具有我指定的值。使用我的 mysql 全局日志,我捕获了实际的物理 sql 并在数据库上手动发出它,并验证它返回了大量的行。
所以 Spring,或者更确切地说是 Hibernate,正在尝试选择它必须删除的行,但它实际上从未发出 DELETE FROM 语句。
根据note on Baeldung 的说法,这个选择语句是正常的,从某种意义上说,Hibernate 将首先选择它打算删除的所有行,然后为每个行发出删除语句。
有谁知道为什么这个派生的 deleteBy 方法不起作用?我的@Configuration 上有@TransactionManagementEnabled,调用的方法是@Transactional。 mysql 日志显示 spring 设置了 autocommit=0,所以看起来事务已正确启用。
我已经通过手动注释派生的删除方法来解决这个问题:
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
}
这行得通。包括交易。但这不应该是,我不应该添加那个 Query 注释。
Here is a person 和我有同样问题的人。然而,Spring 开发人员很快就洗手并将其作为 Hibernate 问题注销,因此在那里找不到解决方案或解释。
哦,作为参考,我使用的是 Spring Boot 2.2.9。
【问题讨论】:
-
在
Long deleteBySystemId(String systemId);上添加@Transactional应该可以工作 -
您应该为您的存储库创建带有
@Transactional和@Service注释的服务。 -
@DirkDeyne 是的,但它没有。结果相同。此外,我不希望我的存储库管理我的事务,我在使用存储库的服务方法中的其他地方有事务注释。此外,无论事务如何,都应该向数据库发出某种“DELETE”语句。没有。
-
@Seldo97 我有这些。这没什么区别。没有发出 DELETE 语句,只有一个 SELECT 语句
标签: spring-boot hibernate spring-data-jpa spring-data