gpt4 book ai didi

java - JPA:即使在 FetchType.LAZY 之后也有 N+1 个查询

转载 作者:行者123 更新时间:2023-11-30 12:02:54 25 4
gpt4 key购买 nike

我已经阅读了几篇介绍如何解决 JPA 中的 n+1 查询问题的文章,但没有一篇对我有用。

当我尝试获取数据时,JPA 进行了 n+1 次查询。

select owner0_.id as id1_1_, owner0_.created_at as created_2_1_, owner0_.updated_at as updated_3_1_, owner0_.name as name4_1_, owner0_.version as version5_1_ from owner owner0_

select cars0_.owner_id as owner_id6_0_0_, cars0_.id as id1_0_0_, cars0_.id as id1_0_1_, cars0_.created_at as created_2_0_1_, cars0_.updated_at as updated_3_0_1_, cars0_.license_no as license_4_0_1_, cars0_.owner_id as owner_id6_0_1_, cars0_.version as version5_0_1_ from car cars0_ where cars0_.owner_id=? [1]

select cars0_.owner_id as owner_id6_0_0_, cars0_.id as id1_0_0_, cars0_.id as id1_0_1_, cars0_.created_at as created_2_0_1_, cars0_.updated_at as updated_3_0_1_, cars0_.license_no as license_4_0_1_, cars0_.owner_id as owner_id6_0_1_, cars0_.version as version5_0_1_ from car cars0_ where cars0_.owner_id=? [2]

下面是代码片段:

@Entity
public class Owner extends BaseEntity implements EntityTransformer<OwnerDto> {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;

@Version
private Long version;

@OneToMany(mappedBy = "owner", fetch = FetchType.LAZY)
private Set<Car> cars;

@Override
public OwnerDto convertToDto() {
OwnerDto ownerDto = new OwnerDto();
ownerDto.setId(this.getId());
ownerDto.setName(this.getName());
ownerDto.setVersion(this.getVersion());
if (this.getCars() != null) ownerDto.setCars(this.getCars().stream().map(Car::convertToDto).collect(Collectors.toSet()));
return ownerDto;
}
}

我的 Car 类如下:

@Entity
public class Car {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String licenseNo;

@Version
private Integer version;

@JoinColumn( name = "owner_id" )
@ManyToOne(fetch = FetchType.LAZY, optional = false)
private Owner owner;
@Override
public CarDto convertToDto() {
CarDto carDto = new CarDto();
carDto.setId(this.getId());
carDto.setLicenseNo(this.getLicenseNo());
carDto.setVersion(this.getVersion());
return carDto;
}
}

所有者服务:

@Service
public class OwnerServiceImpl implements OwnerService {

@Autowired
OwnerRepository ownerRepository;

@Override
public List<Owner> findAll() {
return ownerRepository.findAll();
}
}

所有者 Controller :

@RestController
public class OwnerController {
@Autowired
private OwnerService ownerService;

@GetMapping(value = "/owners", produces = "application/vnd.demo.api.v1+json")
public ResponseEntity<List<OwnerDto>> findAll() {
return ResponseEntity.ok(ownerService.findAll().stream().map(Owner::convertToDto).collect(Collectors.toList()));
}
}

curl :

curl -X POST \
http://localhost:8080/owner \
-H 'Accept: application/vnd.demo.api.v1+json' \
-H 'Content-Type: application/json' \
-H 'Host: localhost:8080' \
-d '{
"name": "pranay5"
}'

curl -X POST \
http://localhost:8080/owner/5/car \
-H 'Accept: application/vnd.demo.api.v1+json' \
-H 'Content-Type: application/json' \
-H 'Host: localhost:8080' \
-d '{
"licenseNo": "MSH-5555"
}'

代码有问题吗?

旁注:@BatchSize(size = 5) JPA 只进行两次查询当我设置 @BatchSize(size = 5) 而不做任何其他更改时,它只对数据库进行两次查询。

select o_.id , o_.created_at, o_.updated_at, o_.name from owner o_ 

select c_.owner_id, c_.id, c_.created_at, c_.updated_at, c_.license_no, c_.owner_id, from car c_ where c_.owner_id in (?, ?, ?, ?, ?) [1,2,3,4,5]

但我的疑问是为什么 FetchType.LAZY 进行 N+1 查询?

代码:https://github.com/pranayhere/exception-demo-mvn

最佳答案

实际上,问题在于您使用了 OwnerRepository 的默认 findAll 并放置了 FetchType.LAZY

因为您在 Owner::convertToDto 中获取汽车,Hibernate 必须获取由于延迟获取而未获取的汽车。

为了避免额外的查询,在 OwnerRepository getAllBy 中创建一个新的 JPA 方法,使用 EntityGraph 来急切地获取查询中的汽车:

public class OwnerRepository extend JpaRepository<Owner, Long> {

@EntityGraph(attributePaths = {
"cars",
})
List<Owners> getAllBy();

}

然后在您的服务中使用它而不是 findAll。

关于java - JPA:即使在 FetchType.LAZY 之后也有 N+1 个查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58168383/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com