项目开发过程中, 遇到了一个文章列表查询速度非常慢的问题。这到底是怎么回事呢?
一路追查下来, 发现竟然是
spring-data-jpa
设计上的问题, 问题稍后说明, 博主先简评一下spring-data-jpa
,spring-data-jpa
很多时候真的很令人劝退, 各种奇奇怪怪的BUG, 功能达不到项目所需, 关联查询灵活性低 , 一些注解失效或难用, 但它简便的开发方式又令人不忍割舍, 正向生成数据库, 通过命名方法对数据库操作,分页排序查询等确实特别好用。总之,
spring-data-jpa
像个爱耍小脾气的漂亮女生, 一开始接触她, 你能享受到各种快乐优雅的开发模式, 觉得她就是我最想要的人, 被她迷得神魂颠倒, 接触久了, 便发现其中的各种毛病, 她不仅满足不了自己, 还可能会给你带来各种烦恼, 让你不禁会问: 为什么你的操作总是令我头秃 ? 她会说: 你去翻遍我所有的文档, 你会发现, 我就是这样不讲理的。这时候, 无奈的你则需要其他框架的辅助,
JdbcTemplate
或Mybatis Plus
能够帮帮你解决问题。spring-data-jpa
优势很明显, 缺点也多, 希望spring-data-jpa
能日趋成熟, 以后做个善解人意的女人, 加大开发灵活性, 满足更多开发者的诉求, 这样博主也会服服帖帖地倒在她的石榴裙下o( ̄▽ ̄)o~嗷~ 。
问题
看代码
Article实体类
1 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
Article投影
主要关注这里1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import com.fasterxml.jackson.annotation.JsonInclude;
import java.time.LocalDate;
import java.util.Set;
/**
* @author mission
* @date 2019/1/27 0027-9:05
*/
public interface ArticleSimpleProjection {
Long getArId();
String getArTitle();
LocalDate getArDate();//时间 默认当前系统时间
(JsonInclude.Include.NON_EMPTY)
Set<ArticleCategoryProjection> getArticleCategories();
}
Article投影查询方法
1 | import com.wteam.gdousd.entity.Article; |
结果
当执行方法以后1
Hibernate: select article0_.ar_id as ar_id1_1_, article0_.ar_content as ar_conte2_1_, article0_.ar_date as ar_date3_1_, article0_.ar_status as ar_statu4_1_, article0_.ar_title as ar_title5_1_ from article article0_ where ( article0_.ar_status = 1) and article0_.ar_status=? and (article0_.ar_title like ?) order by article0_.ar_date desc limit ?
可以看到,article0_.ar_content , article0_.ar_status
等在ArticleSimpleProjection
接口中定义方法没有对应上的数据库字段竟然也被jpa查出 ,其中ar_content
是文章内容,属于大文本字段, 查询多个记录而且还查询该字段的话,查询速度就比原来慢了好几倍。 这不是博主想要的结果, 必须优化!
原因
投影接口中存在返回集合的定义方法, 使得spring-data-jpa
会自动查询所有字段, 目前博主也不知道什么原因(博主没有看过源码)。1
2 (JsonInclude.Include.NON_EMPTY)
Set<ArticleCategoryProjection> getArticleCategories();
因为在投影中存在集合,在ArticleSimpleProjection
接口中就存在了返回Set集合的定义方法getArticleCategories()
, 所以查询投影就会将所有字段查询,这是spring-data-jpa
的设计所致
解决
Article投影
去掉Set集合1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package com.wteam.gdousd.entity.projection;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.time.LocalDate;
/**
* @author mission
* @date 2019/1/27 0027-9:05
*/
public interface ArticleSimpleProjection {
Long getArId();
String getArTitle();
LocalDate getArDate();//时间 默认当前系统时间
(JsonInclude.Include.NON_EMPTY)
ArticleCategoryProjection getArticleCategories();
}
结果
1 | Hibernate: select article0_.ar_id as col_0_0_, article0_.ar_title as col_1_0_, article0_.ar_date as col_2_0_, articlecat2_.ac_id as col_3_0_, articlecat2_.ac_id as ac_id1_2_, articlecat2_.ac_name as ac_name2_2_, articlecat2_.sub_classify as sub_clas3_2_ from article article0_ left outer join relation_article_cate articlecat1_ on article0_.ar_id=articlecat1_.ar_id left outer join article_category articlecat2_ on articlecat1_.arc_id=articlecat2_.ac_id where ( article0_.ar_status = 1) and article0_.ar_status=? and (article0_.ar_title like ?) order by article0_.ar_date desc limit ? |
从结果可见,只要不用set集合,就不会发生jpa查询所有字段的事情。
有时候, 非要把查询结果放在用Set集合中, 就自定义查询吧! 博主认为, 这种情况, 用其他框架 JdbcTemplate
或 Mybatis Plus
实现更好。
结语
目前对数据库操作的框架, 博主使用的是spring-data-jpa
+JdbcTemplate
或 Mybatis Plus
, 基本满足小项目的开发。可是, 各个框架都有优有劣, 博主至今很难做出最佳选择, 真的想全都要呀!可是这样项目体积会变得很庞大哎~~ 如果读者有更好的对数据库操作的框架推荐 或 对本章内容有什么意见建议, 可以在下方评论留言,你的每一言都会让这个无聊博主的人生添上不一样的色彩哦~ヾ( ̄▽ ̄)Bye~Bye~