hibernate的n+1问题已经是一个很常见的问题了。
最近遇到了很多次的n+1问题,总结一下解决办法:
1.ManyToOne中的n+1:
当查询单个的时候,可以使用aaarticlea/png;base64,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" alt="" />来进行让其join查询,
觉得manyToOne的n+1问题同样可以使用这种方法,其中FetchMode有三个参数:
public enum FetchMode {
/**
* use a select for each individual entity, collection, or join load.
* 产生n+1的查询,每个都生成一条查询语句
* n+1条查询
*/
SELECT,
/**
* use an outer join to load the related entities, collections or joins.
* 使用一条outer join进行查询
* 1条查询
*/
JOIN,
/**
* use a subselect query to load the additional collections.
* 使用一条查询list语句进行查询
* 2条查询
*/
SUBSELECT
}
2.查询主体为list的时候的查询
上面的办法应该是可以解决n+1,但是在查询主表的列表是竟然发现还是会产生多一条语句的情况,于是经过百般查找,找到了一种通过hql来解决此问题的方法:
@Entity
@Table(name = "xxxx")
public class ShowInfoEntity implements Serializable {
private static final long serialVersionUID = -5078958740245381213L; // id
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id; // numapi
@OneToOne(fetch = FetchType.EAGER, optional = false, mappedBy = "showInfo")
@Fetch(FetchMode.JOIN)
private ShowNumber numapi;
首先这个是主表,其中与从表ShowNumber有一个关联关系,此关联关系是定义在从表中的。
看到这个类上有配置@Fetch 其在查询单个ShowInfoEntity时是能完美的起作用的,即是join查询,但是在查询List<ShowInfoEntity>时就没有这么幸运了,
会先查询一个List<ShowInfoEntity> 之后在查询n条numapi,
使用left join语句也不能解决问题,
最后找到了left join fetch:
@Query("select t from ShowInfoEntity t LEFT join fetch t.numapi r where t.enable =0 and t.accountId in (?1) and t.timeline<?2")
List<ShowInfoEntity> findByFlush(List<Long> toUsersPredicate, Long time, Pageable page);
顺便说一句,hibernate 的hql语句中的join挺麻烦的,需要先配置好关联关系,然后join 主表.从表
列举一下hql中的join连接
1。左外连接
左外连接(Left Outer Join)查询出左表对应的复合条件的所有记录
2.左外抓取连接
左外抓取连接指定在Hibernate检索数据时,采用抓取的方式,直接将数据加载到与主表对象关联的从表属性中。
3.右外连接
HQL中使用关键字right outer join右外连接
4.内连接
内连接(Inner Join)是指两个表中指定的关键字相等的值才会出现在结果集中的一种查询方式。HQL中使用关键字inner join进行内连接,
5.抓取内连接