大佬教程收集整理的这篇文章主要介绍了如何在使用 Hibernate 的 springboot 中避免本机 SQL 查询的 N+1 问题?,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用 PostgIS 内置程序查询我的数据库,以检索给定位置的最近 @H_172_3@machine。 我必须使用本机 sql,因为 Hibernate 不支持 PostgIS 和 CTE:
@Repository
public interface MachineRepository extends JpaRepository<Machine,Long>{
@query(value =
"with nearest_machines as\n" +
" (\n" +
" SELEct distance_between_days(:ID_day,machine_availability.ID_day) as distance_in_time,\n" +
" ST_distance(geom\\:\\:geography,ST_SetSrID(ST_MakePoint(:longitude,:latitudE),4326)\\:\\:geography) as distance_in_meters,\n" +
" min(ID_day) over (partition by machine.ID) as closest_timeslot_per_machine,\n" +
" machine_availability.ID_day,\n" +
" machine.*\n" +
" from machine\n" +
" join machine_availability on machine.ID = machine_availability.ID_machine\n" +
" where machine_availability.available = true\n" +
" and machine_availability.ID_day >= :today\n" +
" and ST_DWithin(geom\\:\\:geography,4326)\\:\\:geography,1000)\n" +
" )\n" +
"SELEct nearest_machines.*\n" +
"from nearest_machines\n" +
"where ID_day = closest_timeslot_per_machine\n" +
"order by distance_in_time,distance_in_meters\n" +
"limit 20;",nativequery = truE)
List<Machine> findMachinesAccordingToAvailabilitIEs(@Param("longitude") Bigdecimal longitude,@Param("latitude") Bigdecimal latitude,@Param("ID_day") String IDDay,@Param("today") String today);
}
当然,@H_172_3@machine 和 @H_172_3@machineAvailability 是 @Entity
。它们是 @OnetoMany(fetch = FetchType.EAGER)
相关的。我将默认的 LAZY 更改为 EAGER,因为我需要最终 JsON 中的 @H_172_3@machineAvailability。
问题是结果机器又触发了 2 个请求(即著名的 N+1 问题)。
1.我怎样才能在一个请求中解决这个问题?
2.是否可以以某种方式创建我的 JsON 并直接在 @H_172_3@machineController 中返回它?
在 1 个请求中解决这个问题很困难,因为您必须使用 Hibernate 本机 API 来映射可用性集合的表别名。您需要为主查询中的可用性添加连接并执行如下操作:session.createNativeQuery("...").addEntity("m",Machine.class).addFetch("av","m","availabilities")
另一种选择是使用 Blaze-Persistence Entity Views,因为 Blaze-Persistence 支持 CTE 以及 POSTGReSQL 提供的更多优点,这对您来说可能是一个有趣的解决方案。
我创建了该库以允许在 JPA 模型和自定义接口或抽象类定义的模型之间轻松映射,例如类固醇上的 Spring Data projections。这个想法是,您可以按照自己喜欢的方式定义目标结构(域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。
我不知道您的模型,但是对于您的用例,可能的 DTO 模型与 Blaze-Persistence Entity-Views 类似:
@EntityView(Machine.class)
@With(NearestMachineCteProvider.class)
@EntityViewRoot(name = "nearest",entity = NearestMachine.class,condition = "machinEID = VIEW(id)",joinType = JoinType.INNER)
public interface MachineDto {
@IdMapping
Integer getId();
String getName();
@mapping("nearest.distanceInTime")
Integer getDistanceInTime();
@mapping("nearest.distanceInMeters")
Double getDistanceInMeters();
Set<MachineAvailabilityDto> getAvailabilities();
@EntityView(MachineAvailability.class)
interface MachineAvailabilityDto {
@IdMapping
Integer getId();
String getName();
}
class NearestMachineCteProvider implements CTEProvider {
@Override
public void applyCtes(CTEBuilder<?> builder,Map<String,Object> optionalParameters) {
builder.with(NearestMachine.class)
.from(Machine.class,"m")
.bind("distanceInTime").SELEct("CAST_IntegeR(FUNCTION('distance_between_days',:id_day,m.availabilities.idDay))")
.bind("distanceInMeters").SELEct("CAST_DOUBLE(FUNCTION('ST_Distance',m.geom,FUNCTION('ST_SetSrid',FUNCTION('ST_MakePoint',:longitude,:latitudE),4326)))")
.bind("closestTimeslotId").SELEct("min(m.availabilities.idDay) over (partition by m.id)")
.bind("machinEID").SELEct("m.id")
.bind("machineAvailabilityDay").SELEct("m.availabilities.idDay")
.where("m.availabilities.available").eqLiteral(true)
.where("m.availabilities.idDay").geExpression(":today")
.where("FUNCTION('ST_DWithin',4326),1000)").eqLiteral(true)
.end();
}
}
}
@CTE
@Entity
public class NearestMachine {
private Integer distanceInTime;
private Double distanceInMeters;
private Integer closestTimeslotId;
private Integer machinEID;
private Integer machineAvailabilityDay;
}
查询是将实体视图应用于查询的问题,最简单的就是通过 id 查询。
@H_172_3@machineDto a = entityViewManager.find(entitymanager,MachineDto.class,id);
Spring Data 集成允许您像使用 Spring Data projections 一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<MachineDto> findAll(Pageable pageablE);
然后您可以使用 Sort.asc("distanceInTime")
和 Sort.asc("distanceInMeters")
最好的部分是,它只会获取实际需要的状态!
以上是大佬教程为你收集整理的如何在使用 Hibernate 的 springboot 中避免本机 SQL 查询的 N+1 问题?全部内容,希望文章能够帮你解决如何在使用 Hibernate 的 springboot 中避免本机 SQL 查询的 N+1 问题?所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。