Java 如何告诉Springdata存储库';如果某个实体不存在,是否使用s delete方法不引发异常?
我正在使用SpringData的存储库。如果我试图通过一个不存在或从未存在的ID删除一个实体,它会抛出一个异常。因为我不想在删除实体之前检查它是否存在,所以最好它能以静默方式失败。这将使它变得更容易,因为可观察的行为是相同的——在调用之后,实体不再存在。无论它是否被删除或从未存在,我都不在乎 是否有方法修改Java 如何告诉Springdata存储库';如果某个实体不存在,是否使用s delete方法不引发异常?,java,spring,spring-data,Java,Spring,Spring Data,我正在使用SpringData的存储库。如果我试图通过一个不存在或从未存在的ID删除一个实体,它会抛出一个异常。因为我不想在删除实体之前检查它是否存在,所以最好它能以静默方式失败。这将使它变得更容易,因为可观察的行为是相同的——在调用之后,实体不再存在。无论它是否被删除或从未存在,我都不在乎 是否有方法修改delete(EntityId)的默认行为,以便在实体不存在时不会引发异常 表示如果实体不存在,它将抛出异常。更新的答案(在否决投票后) 我最初的回答(如下)实际上是错误的:我对这个问题的理解
delete(EntityId)
的默认行为,以便在实体不存在时不会引发异常
表示如果实体不存在,它将抛出异常。更新的答案(在否决投票后)
我最初的回答(如下)实际上是错误的:我对这个问题的理解也受到官方JavaDoc中缺少EmptyResultDataAccessException
引用的影响(正如Adrian Baker在评论中所报告的)
因此,Yamashiro Rion可能会提出更好的解决方案
if (repository.existsById(entityId)) {
repository.deleteById(entityId);
}
或者这个(没有if
,但可能性能更差):
原始(错误)答案 JavaDocs说,如果提供的参数(id、entity、
Iterable
)为null,而实体不存在,则将抛出IllegalArgumentException
如果需要避免出现IllegalArgumentException
,可以实现一个检查id!=空
:
public void customDelete(ID id) {
if(id != null){
this.delete(id);
}
}
如果您不知道如何添加“Spring数据存储库的自定义实现”,请参阅覆盖该方法:
@Transactional
@Override
public void delete(ID id) {
T entity = findOne(id);
if (entity == null) {
//do something instead of throwing exception ex:
//syso entity does not exist ; return;
}
em.remove(em.merge(entity));
}
需要更少代码的可行解决方案是向存储库接口添加一个新方法,如下所示:
// @Modifying is necessary depending on your version of Spring
@Modifying
@Query(nativeQuery=true, value="DELETE FROM MY_TABLE WHERE ID = ?1")
public void deleteById(IdPrimitiveType id);`
-->要测试这是否可以与JPQL而不是本机SQL一起使用,以允许比默认id类型更复杂的id类型(int、long、String等)我使用@SQLDelete注释来覆盖默认的Hibernate DELETE方法并抑制异常引发:
@javax.persistence.Entity
@Table(name = "mytable")
@Proxy(lazy = false)
@SQLDelete(
sql =
"DELETE FROM mytable " +
"WHERE my_id = ?"
)
public class MyTable {
@javax.persistence.Column(name = "my_id", nullable = false)
@Id
private Long id;
...
}
然后hibernate自动用MyTable对象的实际id替换prepared语句中的“?”,该id映射到表的SQL字段“my_id”
在这种情况下,如果表中的记录不存在,则不会引发异常,只会以静默方式删除0行,如在纯SQL删除查询中,使用
JpaRepository
可以轻松删除实体(如果存在)。在本例中,PostsRepository
扩展了JpaRepository
:
if (postsRepository.existsById(postId)) {
postsRepository.deleteById(postId);
}
如果找不到实体,我使用bellow方法抛出有意义的异常
if (postsRepository.existsById(postId)) {
throw new EntityNotFoundExceptionById("Invlaid Id was provided");
}
postsRepository.deleteById(postId);
EntityNotFoundExceptionById类
@ResponseStatus(HttpStatus.NOT_FOUND)
public class EntityNotFoundExceptionById extends RuntimeException {
public EntityNotFoundExceptionById(String message) {
super(message);
}
}
如果你只需要用一个Id删除,你可以这样做
if(repsoitory.existsById(id)){
repository.deleteById(id)
}
如果您有一个要删除的ID列表,那么您可以使用Java8
List<Long> ids=new ArrayList<>();
ids.stream().filter(id->repository.existsById(id))
.forEach(id->repository.deleteById(id));
List id=new ArrayList();
id.stream().filter(id->repository.existsById(id))
.forEach(id->repository.deleteById(id));
在存储库中,您应使用返回类型整数定义方法:
整数deleteMEntityById(长id);
如果要删除的实体不存在,如果该实体已被删除,您的方法将返回0或1。很抱歉再次询问。如果我写我的customRepository,我还需要接口吗?或者我可以让它成为一个实现存储库接口的抽象类吗?@EhmKah是的,您需要添加一个带有自定义方法的接口,并在一个具体的类中实现它们。文件对此非常清楚。看一看,我看不出这个答案是如何针对一个不存在的实体的问题的?提供的ID参数可能是非null的,但数据存储中不存在这样的实体。这个答案是如何防止这种情况下出现异常的?尽管不幸的是javadoc中没有说明,但org.springframework.data.jpa.repository.support.SimpleParepository实现在实体不存在时抛出EmptyResultDataAccessException。这毫无意义。我无法理解为什么这是正确的答案。这似乎是更好的答案,不使用本机查询,不使用try-catch,而且非常简单。如果使用多个线程,它也可能引发异常(老实说,几乎所有系统都是多线程的)。在“if”语句之后,实体可能会被其他线程删除。此解决方案最终将抛出EmptyResultDataAccessException。不需要进行本机查询,JPQL可以执行批量删除。看起来这是唯一有效的答案,其余的有竞争条件。如果找不到id,则不应抛出not found exception,因为可能有一个作弊来检查这个ID是否存在于你的信息系统中。那不安全。你说的作弊是什么意思?existsById需要在Crudepository中实施。为什么这是一个欺骗?同意existsById来自CrudePository,但当我们使用它并抛出自己定义的EntityNotFoundExceptionById时,编程上是不安全的。
List<Long> ids=new ArrayList<>();
ids.stream().filter(id->repository.existsById(id))
.forEach(id->repository.deleteById(id));