jpa有必要用ManyToOne,ManyToMany吗,一些列头疼的问题

开发背景

为了追求开发效率和代码的美观干净,采用了jpa作为ORM框架。

问题描述

1、jpa在对多表查询支持不是很友好,虽然jpa提供了ManyToOne这种注解来实现多表关联,这样会导致N+1问题,一条主查询sql下出现非常多的子sql,这极大影响查询效率,
2、使用@Lazy也不能避免啊,但用到@Lazy标注的字段时也会在发出一条查询语句,问过数据库连接池的感受吗。
3、@EntityGraph能将实体下标注ManyToOne等注解的属性统一成一条关联查询,可是也有问题:
1.查询出来的字段和表太多了,有时候只需要实体的其中一个标记@ManyToOne的属性,结果把其他的@ManyToMone表也关联上了,说到底细粒度的可控性不好,我明白@NamedAttributeNode可以指定这一整条sql具体关联那些表,但业务不是这么单一,下次需要查其中两个标记@ManyToOne的属性呢。
2.实体下标记@ManyToOne的属性实体A中的属性也标记了@ManyToOne的属性B,这时候使用EntityGraph会继续使用一条sql去把B属性实体找出来,这又回到了N+1问题,这个属性B我不想查,设置@Lazy也避免不要它再查一次
4.实体A下使用了ManyToOne标记属性B以后并设置@Lazy, 当一条sql只需要找到这个B属性的id,那么程序只能获取属性B在查找B中的ID,这会触发懒查询,发出一条sql把B的所有属性全部找出来,我只要这个外键ID啊,不标记@ManyToOne,不是一条sql就搞定了。

我的看法

为了查询高效,没有必要用ManyToOne这种难以控制的注解,直接用@Query的原生sql查找List<Object[]>的结果集,由于jdk8的语法,可以非常高效的转换这个结果集,代码如下:

DTO转换使用Function

@Data
@Accessors(chain = true)
public class ArticleDTO {

    /**
     * 文章ID
     */
    private Integer articleId;

    /**
     * 文章标题
     */
    private String articleTitle;

    /**
     * 文章发布时间
     */
    private Date postTime;

    /**
     * 知识库ID
     */
    private Integer knowledgeId;

    /**
     * 知识库名字
     */
    private String knowledgeName;

    /**
     * 知识库描述
     */
    private String knowledgeDesc;

    /**
     * 知识库封面URL路径
     */
    private String knowledgeCoverUrl;

    public static Function<Object[],ArticleDTO> recommendKnowledge = data -> new ArticleDTO()
            .setArticleTitle(String.valueOf(data[0])).setArticleId(Integer.valueOf(String.valueOf(data[1])))
            .setPostTime(DateUtil.transformStrToDate(String.valueOf(data[2]), "yyyy-MM-dd HH:mm:ss"))
            .setKnowledgeId(Integer.valueOf(String.valueOf(data[3]))).setKnowledgeName(String.valueOf(data[4]))
            .setKnowledgeDesc(String.valueOf(data[5])).setKnowledgeCoverUrl(String.valueOf(data[6]));

}

调用转换代码ArticleDTO.recommendKnowledge.apply(data)

Map<Integer, List<ArticleDTO>> articleDTOS = dataList.stream()
                    .map(data -> ArticleDTO.recommendKnowledge.apply(data))
                    .collect(Collectors.groupingBy(ArticleDTO::getKnowledgeId));

在涉及到多表查询,老老实实写原生sql。不知道各位有什么看法,在平时项目中怎么解决我上面的问题的,jpa实战经验少,自己摸索思考,难免有理解不到位的地方,请各位指点

阅读 6.6k
1 个回答
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进