Spring Data JPA: Repository的DeleteById方法无法工作

7

我是一位有用的助手,可以为您翻译内容。以下是需要翻译的IT技术相关内容:

我在使用Spring Data JPA存储库时遇到了一个问题,但我不明白它的原因。我有以下实体:


@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<Technology> technologies;

针对这个实体,需要一个JPA存储库。 我不理解的是,当我使用Jpa存储库的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=?

感谢您提前帮忙。

1
所以,只是为了确保:您运行生产代码,等待事务提交,然后检查实体是否未从数据存储中删除? - crizzis
1
可能是某个外键约束失败了,导致操作未能完成。请检查您的应用程序日志。 - Panagiotis Bougioukos
1
@Boug 我的日志中没有错误。事实上,我记录了Hibernate的SQL,也没有执行“DELETE”命令。 - Ombrelin
在调用 deleteById() 方法之前,你能否通过 System.out.println 检查它是否使用了正确的参数? - Panagiotis Bougioukos
1
我刚刚做了,它们是正确的,并且与我在数据库中的内容相对应。 - Ombrelin
显示剩余6条评论
1个回答

17

"问题"在于你的映射方式。你的集合是急切地检索。那么为什么会有问题呢?Spring Data JPA中的deleteById首先进行findById操作,在你的情况下,这会急切地加载关联实体。

现在尝试删除实体,但由于它仍然被附加和被另一个实体引用,因此它将被再次持久化,因此删除操作被取消。

可能的解决方案:

  • 使用查询进行删除,并编写自己的查询方法
  • 将关联的一侧标记为lazy

示例:

@Entity
public class Ability {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String name;
    private String color;
    private String image;

    @ManyToOne(
            fetch = FetchType.LAZY
    )
    private Subject subject;

    @OneToMany(
            mappedBy = "ability",
            cascade = CascadeType.ALL,
            orphanRemoval = true,
            fetch = FetchType.LAZY
    )
    private Set<Technology> technologies;
}

@Repository
public interface AbilityRepository extends CrudRepository<Ability, Integer> {
}

控制器:

abilityRepository.deleteById(abilityId);

没有,我没有任何异常。 - Ombrelin
@Ombrelin 然后考虑一下您的数据源是否指向了不同的数据库 ;) - Panagiotis Bougioukos
你能保存一个新项目以确认你正在检查正确的数据源(数据库)吗? - Akif Hadziabdic
@Boug,我真的不这么认为,因为我已经仔细检查了我的凭据,并且当我按照帖子中所说的替换deleteById方法时,删除操作被持久化到数据库中。 - Ombrelin
1
感谢您详细的回答,多亏了您,我现在明白了问题,并且修复确实起作用了。 - Ombrelin
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接