Spring Data JPA:Repository DeleteById 方法不起作用
Spring Data JPA:Repository DeleteById 方法不起作用
我在使用Spring Data JPA Repository时遇到了一个我不理解的问题。我有以下实体:
@Entity
public class Ability {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String color;
private String image;
@ManyToOne(
fetch = FetchType.EAGER
)
private Subject subject;
@OneToMany(
mappedBy = "ability",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.EAGER
)
private Set
}
以及这个实体的JPA Repository。
我不理解的是,当我使用Jpa Repository的deleteById方法时,记录没有从数据库中删除。奇怪的是,在使用内存数据库的集成测试中,它可以正常工作。
如果我使用以下方式重写deleteById方法,它可以正常工作:
@Modifying
@Query("DELETE FROM Ability a WHERE a.id = :id")
void deleteById(@Param("id") Integer id);
但我怀疑我不应该这样做。有没有关于这个方法为什么不能按预期工作的线索?
编辑:添加端点源代码
@RestController
@RequestMapping("/subjects/{subjectId}/abilities")
public class AbilityController {
...
private final AbilityRepository abilityRepository;
private final TechnologyRepository technologyRepository;
private final SubjectRepository subjectRepository;
public AbilityController(AbilityRepository abilityRepository, TechnologyRepository technologyRepository, SubjectRepository subjectRepository) {
this.abilityRepository = abilityRepository;
this.technologyRepository = technologyRepository;
this.subjectRepository = subjectRepository;
}
@DeleteMapping("{abilityId}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteAbility(@PathVariable("subjectId") Integer subjectId, @PathVariable("abilityId") Integer abilityId) {
if (!abilityRepository.existsAbilityBySubjectId(subjectId, abilityId)) {
throw new ResourceNotFoundException(String.format("No ability with Id : %s", abilityId));
}
abilityRepository.deleteById(abilityId);
}
...
}
编辑:添加Hibernate SQL
Hibernate:
select
ability0_.id as id1_0_0_,
ability0_.color as color2_0_0_,
ability0_.image as image3_0_0_,
ability0_.name as name4_0_0_,
ability0_.subject_id as subject_5_0_0_,
subject1_.id as id1_7_1_,
subject1_.icon as icon2_7_1_,
subject1_.image as image3_7_1_,
subject1_.name as name4_7_1_,
technologi2_.ability_id as ability_4_8_2_,
technologi2_.id as id1_8_2_,
technologi2_.id as id1_8_3_,
technologi2_.ability_id as ability_4_8_3_,
technologi2_.image as image2_8_3_,
technologi2_.name as name3_8_3_
from
ability ability0_
left outer join
subject subject1_
on ability0_.subject_id=subject1_.id
left outer join
technology technologi2_
on ability0_.id=technologi2_.ability_id
where
ability0_.id=?
Hibernate:
select
abilities0_.subject_id as subject_5_0_0_,
abilities0_.id as id1_0_0_,
abilities0_.id as id1_0_1_,
abilities0_.color as color2_0_1_,
abilities0_.image as image3_0_1_,
abilities0_.name as name4_0_1_,
abilities0_.subject_id as subject_5_0_1_
from
ability abilities0_
where
abilities0_.subject_id=?
Hibernate:
select
technologi0_.ability_id as ability_4_8_0_,
technologi0_.id as id1_8_0_,
technologi0_.id as id1_8_1_,
technologi0_.ability_id as ability_4_8_1_,
technologi0_.image as image2_8_1_,
technologi0_.name as name3_8_1_
from
technology technologi0_
where
technologi0_.ability_id=?
提前感谢。
Spring Data JPA中的Repository.deleteById方法不起作用
问题是你的映射有问题。你的集合是急加载的。为什么会有问题呢?因为Spring Data JPA中的deleteById首先会执行findById,而在你的情况下,它会急加载关联的实体。
现在实体正在尝试被删除,但由于它仍然被另一个实体所引用和关联,它会被再次持久化,因此删除操作被取消。
可能的解决方法有:
- 使用查询删除,并为此编写自己的查询方法
- 将关联的一方标记为延迟加载
示例代码如下:
public class Ability { (strategy = GenerationType.AUTO) private Integer id; private String name; private String color; private String image; ( fetch = FetchType.LAZY ) private Subject subject; ( mappedBy = "ability", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY ) private Set<Technology> technologies; } public interface AbilityRepository extends CrudRepository<Ability, Integer> { }
控制器代码如下:
abilityRepository.deleteById(abilityId);
是的,我已经有一个JpaRepository来操作我的实体了。当我使用现有的deleteById方法时,删除操作没有被持久化到数据库中。
你有任何异常吗?
不,我没有任何异常。
那么请考虑一下你的数据源是否指向了另一个数据库 😉
你能在abilityRepository.deleteById(abilityId)之后添加abilityRepository.flush()来尝试吗?
添加flush()后的行为与之前完全相同。
为了确认你正在检查正确的数据源(数据库),你可以尝试保存一个新的项目吗?
我真的不认为是这样,因为我仔细检查了我的凭据,而且当我按照帖子中所说的替换deleteById方法时,删除操作被持久化到了数据库中。
是的,我刚刚尝试了一下,在数据库中插入一个新项目的操作按预期工作。
你可以启用Hibernate SQL日志记录,以检查是否将查询发送到数据库吗?
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
让我们在聊天中继续讨论。
感谢你详细的答案,多亏了你,我理解了问题,并且修复方法确实起作用。
我可以确认,在我的情况下,使用FetchType.LAZY解决了类似的问题。
通过使用FetchType.LAZY解决了我的问题,谢谢。