阅读 478

spring-data-jpa原生sql查询

随着技术的发展,持久层框架也越来越趋于成熟,从Mybatis到JPA,新的技术都是使我们使用起来更加方便简单.就拿 JPA来说,由于JPA自带的方法可以满足大部分日常开发中的crud,所以深得程序员们的喜爱,但是,有利就有弊.

近日我在开发中就遇到了一个关于查询效率缓慢的问题.

问题描述:

1.在开发环境有个业务,列表页加搜索框功能,然后列表中数据是使用JPA的findAll()方法查询2万数据,竟然整整需要7s,JPA虽然好用简便,但是findall相当于是 SELECT * FROM tb where a,b,c,这种全表扫描效率低是肯定的,而且是把表中所有字段都查了一遍,分页后依旧不是很快,但是业务中只需要几个字段而已,这其实就是极大的耗费资源.

2.自定义sql语句下where条件该如何拼接并且判空,类似于mybatis的if null.

3.自定义sql语句下如何进行分页.

解决方案:

1.此刻加索引肯定是不行的,where条件并不固定(所有搜索框为空时是全查),所以就想到了利用JPA的@Query功能,将select * 替换为具体需要的字段,select a,b,c from tb,就是写原生sql语句,此时效率瞬间提高了不少,大概耗时1.2s,所以select * from tb 能不用则不用吧.性能问题解决了.

2.where条件的判空,就是当条件不为null时进行查询,结合google加实践我弄出了这个方法:

@Query(value = " select name,age,sex where if(?1!= '',name = ?1,1=1) and if(?2!= null,age = ?2,1=1)", nativeQuery = true)
 List<Object[]> countCase(String name, Integer age, String sex)
复制代码

if(?1 !='',name=?1,1=1) 代表传入的参数name如果不为""(String类型空是""而不是null)将参数传入name,如果为空时显示1=1 代表参数为真,对查询结果不产生作用,所传参数顺序有要求.

3.查看文档之后决定直接用JpaRepository 的 Pageable 来直接实现:

参考文档(Example 51. Declare native count queries for pagination at the query method using [@Query])

(docs.spring.io/spring-data…)

@Query(value = " select name,age,sex where if(?1!= '',name = ?1,1=1) and if(?2!= null,age = ?2,1=1) /*#pageable*/",countQuery = "select count(*) where if(?1!= '',name = ?1,1=1) and if(?2!= null,age = ?2,1=1)",nativeQuery = true)
 Page<Object[]> countCase(String name, Integer age, String sex,Pageable pageable)
复制代码

countQuery用来获取总条数.

**/#pageable/**在此处时必须添加,推测是JPA可能需要pageable字符来使工程正常启动,如果不加则会启动发生异常.

以上仅限于mysql