【发布时间】:2021-07-21 22:25:52
【问题描述】:
我正在使用 POSTGIS 内置函数查询我的数据库,以检索给定位置的最接近的Machines。
我必须使用原生 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, ST_SetSrid(ST_MakePoint(:longitude, :latitude), 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);
}
当然,Machine 和 MachineAvailability 是 @Entity 的。它们与@OneToMany(fetch = FetchType.EAGER) 相关。我将默认 LAZY 更改为 EAGER,因为我需要在最终 JSON 中使用 MachineAvailability。
问题在于它触发了结果机器的另外 2 个请求(即著名的 N+1 问题)。
1.我怎样才能在一个请求中解决这个问题?
2.是否有可能以某种方式创建我的 JSON 并直接在 MachineController 中返回它?
【问题讨论】:
-
这里有些不对劲,因为如果您发出的是原生 SQL 查询,那么 Hibernate N+1 问题根本不应该是一个问题,甚至应该是不可能的。是什么让您认为这里发生了 N+1?
-
因为我在日志中看到了请求。
-
那么它们来自您的原始 SQL 查询,而不是来自 Hibernate/JPA。 AFAIK 当您将 native 设置为 true 时,您基本上只是在执行本机 JDBC 准备语句。
-
他们来自@OneToMany(fetch = FetchType.EAGER)。当我切换到 LAZY 时,问题消失了,但我没有可用性!!!
标签: postgresql spring-boot hibernate postgis rawsql