前面的几篇文章分别介绍了CURD中的增删改,接下来进入最最常见的查询篇,看一下使用jpa进行db的记录查询时,可以怎么玩
本篇将介绍一些基础的查询使用姿势,主要包括根据字段查询,and/or/in/like/between
语句,数字比较,排序以及分页
I. 环境准备
在开始之前,当然得先准备好基础环境,如安装测试使用mysql,创建SpringBoot项目工程,设置好配置信息等,关于搭建项目的详情可以参考前一篇文章
下面简单的看一下演示添加记录的过程中,需要的配置
1. 表准备
沿用前一篇的表,结构如下
1 | CREATE TABLE `money` ( |
2. 项目配置
配置信息,与之前有一点点区别,我们新增了更详细的日志打印;本篇主要目标集中在添加记录的使用姿势,对于配置说明,后面单独进行说明
1 | ## DataSource |
3. 数据准备
数据修改嘛,所以我们先向表里面插入两条数据,用于后面的操作
1 | INSERT INTO `money` (`id`, `name`, `money`, `is_deleted`, `create_at`, `update_at`) |
II. Query基本使用姿势
下面进入简单的查询操作姿势介绍,单表的简单and/or/in/compare查询方式
1. 表关联POJO
查询返回的记录与一个实体类POJO进行绑定,借助前面的分析结果,如下
1 |
|
上面类中的几个注解,说明如下
@Data
属于lombok注解,与jpa无关,自动生成getter/setter/equals/hashcode/tostring
等方法@Entity
,@Table
jpa注解,表示这个类与db的表关联,具体匹配的是表money
@Id
@GeneratedValue
作用与自增主键@Column
表明这个属性与表中的某列对应@CreateDate
根据当前时间来生成默认的时间戳
2. Repository API声明
接下来我们新建一个api继承自CurdRepository
,然后通过这个api来与数据库打交道,后面会在这个类中添加较多的查询方法
1 | public interface MoneyBaseQueryRepository extends CrudRepository<MoneyPO, Integer> { |
3. 使用姿势
a. 根据id查询
CrudRepository
已经提供的功能,根据主键id进行查询,对于使用者而言,没有什么需要额外操作的,直接访问即可
1 | private void queryById() { |
b. 根据字段查询
除了根据主键查询,实际的业务场景中,根据某个字段进行查询的case,简直不要更多,在jpa中可以怎么做呢?
- 在
Repository
接口中声明一个方法,命名规则为 - findByXXX 或者 queryByXXX (注意这里的xxx用POJO中的成员名替换,表示根据这个成员进行查询)
一个简单的case,如果我希望实现根据name进行查询,那么在MoneyBaseQueryRepository
中添加下面两个方法中的任意一个都可以
1 | /** |
如果需要多个成员的查询呢?也简单,形如findByXxxAndYyyy
相当于sql中的where xxxx=? and yyy=?
如我们也可以增加下面两个方法(一个and、一个or查询)
1 | /** |
一个简单的测试case可以如下
1 | private void queryByField() { |
执行之后输出结果如下,下面也包括了对应的sql,便于理解
1 | Hibernate: select moneypo0_.id as id1_0_, moneypo0_.create_at as create_a2_0_, moneypo0_.is_deleted as is_delet3_0_, moneypo0_.money as money4_0_, moneypo0_.name as name5_0_, moneypo0_.update_at as update_a6_0_ from money moneypo0_ where moneypo0_.name=? |
c. like查询
上面的查询方式为等值查询,当在sql中除了等值查询(即=查询)之外,还有各种比较查询,不等查询以及like语句,在jpa中也比较简单,在repository
定义的方法名,加一个like即可
1 | /** |
使用的时候,需要稍微注意一下,根据实际情况决定要不要加上 ‘%’
1 | private void queryByLike() { |
输出结果为
1 | Hibernate: select moneypo0_.id as id1_0_, moneypo0_.create_at as create_a2_0_, moneypo0_.is_deleted as is_delet3_0_, moneypo0_.money as money4_0_, moneypo0_.name as name5_0_, moneypo0_.update_at as update_a6_0_ from money moneypo0_ where moneypo0_.name like ? |
d. in查询
对于in查询,CurdRepository
提供了根据主键id的查询方式,直接调用findAllById
即可,如果是其他的,可以通过声明一个接口的方式来支持
1 | /** |
测试case如下
1 | // in 查询 |
输出结果
1 | Hibernate: select moneypo0_.id as id1_0_, moneypo0_.create_at as create_a2_0_, moneypo0_.is_deleted as is_delet3_0_, moneypo0_.money as money4_0_, moneypo0_.name as name5_0_, moneypo0_.update_at as update_a6_0_ from money moneypo0_ where moneypo0_.id in (? , ? , ?) |
e. 比较查询
数字的比较查询,比如大于等于,大于,小于,小于等于,between,下面的三个方法声明,应该能直观表示这种方式可以如何写
1 | /** |
下面是简单的映射关系
>
:xxGreaterThan
>=
:xxGreaterThanEqual
<
:xxLessThan
<=
:xxLessThanEqual
!=
:xxNot
between a and b
:xxIsBetween
测试case如下
1 | private void queryByCompare() { |
输出结果为
1 | Hibernate: select moneypo0_.id as id1_0_, moneypo0_.create_at as create_a2_0_, moneypo0_.is_deleted as is_delet3_0_, moneypo0_.money as money4_0_, moneypo0_.name as name5_0_, moneypo0_.update_at as update_a6_0_ from money moneypo0_ where moneypo0_.id<=? |
f. 排序
排序也属于基本查询的case了,jpa的实现中,通过加上OrderByXxxAsc/Desc
的方式来决定根据什么进行升序or降序
1 | /** |
在根据多个列进行排序时,需要注意的是不能写多个 OrderBy
而是直接在OrderBy
后面加上对应的xxxAscyyyDesc
测试代码如
1 | private void queryWithSort() { |
输出结果如下
1 | Hibernate: select moneypo0_.id as id1_0_, moneypo0_.create_at as create_a2_0_, moneypo0_.is_deleted as is_delet3_0_, moneypo0_.money as money4_0_, moneypo0_.name as name5_0_, moneypo0_.update_at as update_a6_0_ from money moneypo0_ where moneypo0_.money=? order by moneypo0_.id desc |
g. 分页查询
分页有两种方式,一个是查询最大的多少条数据,一个是正常的limit/offset方式,下面是一个简单的实例demo
1 | /** |
对于分页而言,通过传入参数Pageable来表明即可
测试case如
1 | private void queryWithPageSize() { |
输出结果为
1 | Hibernate: select moneypo0_.id as id1_0_, moneypo0_.create_at as create_a2_0_, moneypo0_.is_deleted as is_delet3_0_, moneypo0_.money as money4_0_, moneypo0_.name as name5_0_, moneypo0_.update_at as update_a6_0_ from money moneypo0_ where moneypo0_.id>? limit ? |
4. 小结
主要介绍了jpa的查询的最基本使用方式,主要是根据规则定义方法名的方式来实现sql的效果, 下表示一个简单的对比小结
方法名 | 说明 | 等效sql |
---|---|---|
findByXxx |
表示根据列Xxx 等于传参构建sql |
where xxx= ? |
findByXxxAndYyy |
根据多个列进行查询 | where xxx=? and yyy=? |
findByXxxOrYyy |
根据多个列实现or查询 | where xxx=? or yyy=? |
findByXxxLike |
like查询,需要注意查询条件中加% | where xxx like |
findByXxxIn |
in查询 | where Xxx in () |
findByXxxGreaterThan |
大于 | where xxx > ? |
findByXxxGreaterThanEqual |
大于等于 | where xxx >= ? |
findByXxxLessThan |
小于 | where xxx < ? |
findByXxxLessThanEqual |
小于等于 | where xxx <= ? |
findByXxxNot |
不等于 | where xxx != ? |
findByXxxIsBetween |
between查询 | where xxx between ? and ? |
OrderByXxxDesc |
排序 | order by xxx desc |
topN |
分页,表示获取最前面的n条 | limit n |
此外还有一个分页的方式是传参Pageable
,来指定具体的分页
我们常见的查询操作中,除了上面的一些case之外,还有一些是我们没有提到的,如下面的一些使用姿势,则会在后面的文章中引入
group by
distinct
join
- 各种函数的支持(sum,max,min,avg…)
- 查询部分表中部分字段时
- 统计查询
II. 其他
0. 源码&相关博文
源码
- 工程:https://github.com/liuyueyi/spring-boot-demo
- module: https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/102-jpa
相关博文
- mysql之锁与事务详解
- Spring学习之事务的使用姿势
- Spring学习之事务管理与传播属性
- 190612-SpringBoot系列教程JPA之基础环境搭建
- 190614-SpringBoot系列教程JPA之新增记录使用姿势
- 190623-SpringBoot系列教程JPA之update使用姿势
- 190702-SpringBoot系列教程JPA之delete使用姿势详解
1. 一灰灰Blog
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
- 一灰灰Blog个人博客 https://blog.hhui.top
- 一灰灰Blog-Spring专题博客 http://spring.hhui.top
Gitalking ...