【问题标题】:Spring Data JPA : Repository DeleteById method not workingSpring Data JPA:存储库 DeleteById 方法不起作用
【发布时间】:2021-04-19 00:49:17
【问题描述】:

我的 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 Repository 的 deleteById 方法时,记录并没有从数据库中删除。奇怪的是,它在我使用 InMemory 数据库的集成测试中运行良好。 如果我用以下内容覆盖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);
    }
    ...
}

编辑:添加休眠 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=?

提前致谢

【问题讨论】:

  • 所以,只是为了确保:您运行生产代码,等待事务提交,然后检查该实体是否没有从数据存储中删除?
  • 可能某些外键约束失败并且没有完成。检查您的应用程序的日志
  • @crizzis 是的。我假设当 HTTP 请求被解析时,事务已经被提交。
  • @Boug 我的日志中没有错误。实际上我记录了 Hibernate 的 SQL 并且没有执行“DELETE”命令
  • 我刚刚做了,它们是正确的,并且与我在数据库中的内容相对应

标签: java spring spring-boot jpa spring-data-jpa


【解决方案1】:

“问题”是您的映射。您的收藏被急切地检索。现在为什么这会是一个问题? Spring Data JPA 中的 deleteById 首先执行 findById,在您的情况下,它会急切地加载关联的实体。

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

可能的解决方案:

  • 使用查询删除并为此编写您自己的查询方法
  • 将关联的任一侧标记为惰性

例子:

@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);

【讨论】:

  • 是的,我已经为我的实体创建了一个 JpaRepository。那是当我使用现有的deleteById 时,删除不会持久化到数据库中。
  • 你有什么例外吗?
  • 不,我没有任何例外
  • @Ombrelin 然后考虑您的数据源指向不同的数据库;)
  • 感谢您的详细回答,感谢您,我明白了这个问题,并且修复确实有效。
猜你喜欢
  • 2021-05-13
  • 2019-03-02
  • 2012-06-02
  • 2018-07-26
  • 2017-08-20
  • 2015-12-29
  • 1970-01-01
  • 2017-01-06
  • 1970-01-01
相关资源
最近更新 更多