Spring Data JPA:Repository DeleteById 方法不起作用

9 浏览
0 Comments

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

}

以及这个实体的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=?

提前感谢。

0
0 Comments

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解决了我的问题,谢谢。

0