程序问答   发布时间:2022-06-02  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了如何在使用 Hibernate 的 springboot 中避免本机 SQL 查询的 N+1 问题?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决如何在使用 Hibernate 的 springboot 中避免本机 SQL 查询的 N+1 问题??

开发过程中遇到如何在使用 Hibernate 的 springboot 中避免本机 SQL 查询的 N+1 问题?的问题如何解决?下面主要结合日常开发的经验,给出你关于如何在使用 Hibernate 的 springboot 中避免本机 SQL 查询的 N+1 问题?的解决方法建议,希望对你解决如何在使用 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,请注明来意。