如何通过单个查询 select 不相关的实体
How to select unrelated entities with a single query
假设我们有 5 个 table,它们彼此之间没有任何关系,但它们都共享同一列。我们将 table 命名为 ClojureConf
、KotlinConf
、ScalaConf
、GroovyConf
、JavaConf
。他们都有一列UserId
。其他列的数量和数据类型各不相同。给定用户可能参加了零个或多个会议。
任务只是 select 给定 UserId
的 5 table 中每一个的所有记录,将它们转换为 DTO,并将 return 作为 json。
目前,代码对数据库进行了 5 次访问,以从每个 table.
中获取结果列表
hibernate/jpa 中是否有库支持,什么可以单次访问数据库?目标是提高性能。
是否可以为看起来类似于此的实体定义投影:
interface ConfAttended {
List<ClojureConf> getClojureConfs();
List<KotlinConf> getKotlinConfs();
List<ScalaConf> getScalaConfs();
List<GroovyConf> getGroovyConfs();
List<JavaConf> getJavaConfs();
}
和一个可以 select 并一次性映射结果的存储库
interface ConfAttendedDAO extends JpaRepository<User, Long> {
@Query("SELECT c, k, s, g, j FROM ClojureConf c " +
"JOIN KotlinConf k ON c.UserId = k.UserId " +
"JOIN ScalaConf s ON c.UserId = s.UserId " +
"JOIN GroovyConf g ON c.UserId = g.UserId " +
"JOIN JavaConf j ON c.UserId = j.UserId " +
"WHERE c.UserId = :userId")
ConfAttended findByUserIdForProjection(@Param("userId") long userId);
}
?
我最终遇到了这样的查询:
interface ConfAttendedDAO extends JpaRepository<User, Long> {
@Query("SELECT c, k, s, g, j FROM User u " +
"LEFT JOIN ClojureConf c ON c.UserId = :userId " +
"LEFT JOIN KotlinConf k ON k.UserId = :userId " +
"LEFT JOIN ScalaConf s ON s.UserId = :userId " +
"LEFT JOIN GroovyConf g ON g.UserId = :userId " +
"LEFT JOIN JavaConf j ON j.UserId = :userId " +
"WHERE u.Id = :userId")
List<Object[]> findAllByUserId(@Param("userId") long userId);
}
Hibernate 负责将行映射到实体。每个 Object[]
都将所有 5 个实体(或空值)作为其元素。从 User
中选择是强制查询到 return 个结果。否则,如果第一个 table return 什么都没有 - 整个查询 return 什么都没有。另一个缺点是,如果一个 table 有 10 个结果而另一个有 1 个,则结果较少的 table 会使它们重复。
至于性能(做这一切的唯一意义),获取和处理结果比 5 个单独的 SELECT
s 快 4-5 倍。
假设我们有 5 个 table,它们彼此之间没有任何关系,但它们都共享同一列。我们将 table 命名为 ClojureConf
、KotlinConf
、ScalaConf
、GroovyConf
、JavaConf
。他们都有一列UserId
。其他列的数量和数据类型各不相同。给定用户可能参加了零个或多个会议。
任务只是 select 给定 UserId
的 5 table 中每一个的所有记录,将它们转换为 DTO,并将 return 作为 json。
目前,代码对数据库进行了 5 次访问,以从每个 table.
中获取结果列表hibernate/jpa 中是否有库支持,什么可以单次访问数据库?目标是提高性能。
是否可以为看起来类似于此的实体定义投影:
interface ConfAttended {
List<ClojureConf> getClojureConfs();
List<KotlinConf> getKotlinConfs();
List<ScalaConf> getScalaConfs();
List<GroovyConf> getGroovyConfs();
List<JavaConf> getJavaConfs();
}
和一个可以 select 并一次性映射结果的存储库
interface ConfAttendedDAO extends JpaRepository<User, Long> {
@Query("SELECT c, k, s, g, j FROM ClojureConf c " +
"JOIN KotlinConf k ON c.UserId = k.UserId " +
"JOIN ScalaConf s ON c.UserId = s.UserId " +
"JOIN GroovyConf g ON c.UserId = g.UserId " +
"JOIN JavaConf j ON c.UserId = j.UserId " +
"WHERE c.UserId = :userId")
ConfAttended findByUserIdForProjection(@Param("userId") long userId);
}
?
我最终遇到了这样的查询:
interface ConfAttendedDAO extends JpaRepository<User, Long> {
@Query("SELECT c, k, s, g, j FROM User u " +
"LEFT JOIN ClojureConf c ON c.UserId = :userId " +
"LEFT JOIN KotlinConf k ON k.UserId = :userId " +
"LEFT JOIN ScalaConf s ON s.UserId = :userId " +
"LEFT JOIN GroovyConf g ON g.UserId = :userId " +
"LEFT JOIN JavaConf j ON j.UserId = :userId " +
"WHERE u.Id = :userId")
List<Object[]> findAllByUserId(@Param("userId") long userId);
}
Hibernate 负责将行映射到实体。每个 Object[]
都将所有 5 个实体(或空值)作为其元素。从 User
中选择是强制查询到 return 个结果。否则,如果第一个 table return 什么都没有 - 整个查询 return 什么都没有。另一个缺点是,如果一个 table 有 10 个结果而另一个有 1 个,则结果较少的 table 会使它们重复。
至于性能(做这一切的唯一意义),获取和处理结果比 5 个单独的 SELECT
s 快 4-5 倍。