JPA在多表联查上的一些坑

Author Avatar
Sean Yu 4月 11, 2020
  • 在其它设备中阅读本文章

JPA的使用场景 (仅针对查询)

最基本的场景

这种情况比较简单,一般针对一张数据库表建立对应的Java \@Entity class,把针对表的SQL操作转化为JPA 的JPQL / Native SQL / Criteria API 即可。

如果表有单一主键就更简单了,把它作为JPA的\@Id字段。如果没有单一主键,需要确定一个唯一性索引(可能是一列或多列)来作为JPA 的\Id 字段或字段组合。

多表联查的场景

对于多张表的联合查询,就没法做到Java \@Entity class和数据库表(\@Table)一一对应了。这个时候可以针对多张数据库表建立一个数据库视图View, 然后使

Java \@Entity class和 View (\@Table) 对应,其中\@Table里指定View的名字。

有些时候,可能会因为权限或其他原因,没法对数据库表建View。这个时候可以仅把\@Entity class作为对接SQL 查询结果的实体类。在这个实体类中只加\@Entity 不加\@Table 的annation.

如果是用JPA Native SQL 的方式,此用法有点类似于Mybatis。

多表联查中的一些坑

确定JPA \@Id 字段或字段组合
对于多表联查的情况,如果多个表中有一个是主表,并且主表有主键或唯一性索引的话,比较简单,其实和单表查询的情况相同;

如果多个表中没有明显的主表,而且联合查询的结果集的唯一性字段来自于多个表,就稍微复杂了,需要基于对业务数据的理解 / 猜测 + 排除法多次尝试了。从而确定一个最小的字段组合来代表结果集的唯一性索引。

(系统的遗留代码中有很多多表联查,且表没有主键的情况)

实践中发现,如果指定的\@Id字段或字段组合不唯一,JPA返回的数据记录总数看似正确,数据其实是不准确的。

\@Id 字段组合中有字段/列有空值的情况
JPA \@Id 字段组合中有字段为NULL 值会导致JPA返回一个NULL Object,这种情况下,如果直接对JPA返回的结果做操作,则会抛出意想不到的NullPointerException。

对于\@Id 字段组合中有字段为NULL 值的情况,其实可以分为两种:

错误数据 - 判断错误数据的标准是什么呢?在全部数据中占比很小(比如1 万条数据里有十几条某列为空值的情况);基于对业务的理解,某些值为空是业务无意义的。
有效数据 - 占比高,比如80%的数据某个列都是NULL,这个肯定不是错误数据了 (也可能是当初数据库设计的问题???)
其实针对以上两种情况,处理方式也有区别:

对于错误数据,可以考虑在做SQL查询的时候去过滤。
对于有效数据,可能需要借助 SQL COALESCE() 函数 来对数据进行转换。