在 Spring 内做 JOIN 联查

数据库 ORM 框架大部分情况下都是为了方便进行数据库操作——只需要操作一个结构体,就可以将修改同步至数据库中,增删改查都可以被屏蔽为对一个对象的操作。

但是由于结构和数据库深度绑定,因此对于类似于多表联查的需求反而变得更麻烦:

  • 一方面是关联的条件难以描述
  • 另一方面是返回的数据结构没有适当的结构存储

简单来说,大部分类似的需求,都需要使用外键来实现,也就是 OneToOne、OneToMany、ManyToOne、ManyToMany 之类的
但是有时候数据之间并不希望有外键这个关系,因此只能回归原生 SQL 查询
(这么看,框架本身反而增加了工作量)

这里的 SQL 与标准的 SQL 并不完全等价,因为结果必然会返回为一个对象,因此SELECT部分,应该是一个对象的构造函数(按照 Java 的写法)。
只需要提前声明一个类,并且拥有相应入参个数和类型的构造函数,那么就可以将查询结果存入一个该类型的对象中。

@Service
@Component
public class XXXService {
   
    @PersistenceContext
    private EntityManager em;

    public List<XXX> search(long start, long end) {
        StringBuilder sb = new StringBuilder();
        sb.append(
            "SELECT new XXX(a.id, a.name, a.id2, b.name2) FROM A a, B b WHERE a.id2=b.id"
        );

        if (start != 0 && end != 0) {
            sb.append(" AND a.timestamp BETWEEN");
            sb.append(start);
            sb.append(" AND ");
            sb.append(end);
        } else if (start != 0) {
            sb.append(" AND a.timestamp > ");
            sb.append(start);
        } else if (end != 0) {
            sb.append(" AND a.timestamp < ");
            sb.append(end);
        }
        List<XXX> res = em.createQuery(sb.toString()).getResultList();
        return res;
    }
}

参考资料