Spring data JPA是一个好东西,但是对于很多习惯于写SQL,直接怼数据库的人来说,这个真的用不习惯,还被一致认为是一个不易于程序员发展的技术。因为JPA提供了标准的封装,在操作数据库的时候,不需要写SQL,完全通过操作对象即可完成。久而久之,SQL就会被慢慢的遗忘,生疏,等以后面试的时候,也许这就是上升的一个短板。现在各大公司对JPA用的都很少,除非是这个公司的系统涉及到几种数据库,随时有可能出现数据库之间的迁移,为了SQL的兼容性使用JPA。这也是JPA的一个最大优点,不是之一。至少我是这么认为的。在这篇博文里面,我们就来聊聊,不要通过写任何SQL来实现对数据库的基本操作。
核心Repository
Spring Data库的核心接口是Repository
,使用domain类去管理,domain类中的id类型作为类型参数,这个接口主要作为一个标记接口,依靠具体的类型运作并帮助发现接口。其直接集成接口为CrudRepository
,提供了丰富的CRUD功能去管理实体类。
然后就是用于分页排序的PagingAndSortRepository
接口类,它继承于CrudRepository
接口。提供了丰富的分页和排序的功能API。说丰富其实就两个功能,不过对付基本的排序功能还是能够完成使用的。
最后就是JpaRepository
,这个类中也有封装基本的方法。这个类是继承了PagingAndSortRepository
接口,同时也继承了QueryByExampleExecutor
执行器接口。
继承图关系如下:
JPA的上手使用
JPA的依赖
这里只基于整合Spring boot方式的JPA依赖引入,如果使用Spring MVC的可以到网上找一下需要哪些依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
JPA的配置
不管是JPA还是Mybatis都是需要提前完成一些配置,对于JPA来说比较简单,进行一下配置即可。
在基于Spring boot的配置:
@EnableJpaRepositories
public class JpaConfig{}
主要是这个注解,一般是放在XxxxApplication
启动类上。
在基于非Spring boot的项目配置,可以用XML来实现:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jpa:repositories base-package="com.acme.repositories"/>
</beans>
这里基于XML配置的方式,实话说我是没有用过的,不过大概可以看的出来类似于配置Spring的@ComponentScan
配置类扫描的基础路径。在@EnableJpaRepositories
中也是有basePackages
属性的。
之所以这里基于XML方式的配置不多说,是因为现在着手开发的项目都是基于Spring boot,另外Spring boot是将来发展的一个趋势,不,不是将来,现在就有绝大部分项目(新启动的项目)都会使用Spring boot。所以基于XML方式的,用到才具体研究吧,上面的配置是摘抄于Spring data JPA官方文档。
另外还有一些JPA的配置信息和数据库的配置信息在第一篇文章里面有体现,这里不赘述。
创建Entity实体类
通过Entity实体类指定对应的数据表,和表的字段形成映射关系。简单的写法如下:
@Entity
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "user_name")
private String userName;
@Column(name = "phone")
private String phone;
@Column(name = "age")
private Integer age;
}
这种提供注解的方式指定数据表和表字段的映射关系,在本系列的第一篇文章说过了,这里就不详细说拉。
创建Repository接口
这里在创建对应的UserRepository
接口类的时候必须继承Repository
接口或者其子类接口。这个需要看需求,如果不需要使用本身提供的CRUD方法、分页、排序等功能的话,直接继承Repository
接口即可。但是对于正常来说,原生提供的API多少是会用上一点的,即使用不上,自己拥有也不是一件坏事,所以在项目开发中都是直接继承JpaRepository
接口。在泛型里面执行对应的实体类Entity和主键的类型。这两个参数很重要,不可少。
public interface UserRepository extends JpaRepository<User,Long>{
//……
}
到这里整个JPA的信息都构建结束,需要使用什么操作,就在UserRepository
接口里面加入相应的方法即可。
基于方法的骚操作
这部分内容是这篇文章的重点,就是通过不同方法名的组合来实现SQL自动的生成,不需要自己写一行SQL代码。接下来说几种常用的情况来引入一下。
find…By…
在查询语句的时候,可能会不带条件,可能会带条件,这里在看看find…By…
的基本用法。
User findById(Long id);//1
List<User> findTop10ByAge(Integer age);//2
User findByUserNameAndPhone(String userName,String phone);//3
通过上面的3个方法可以大体了解一下find…By…的用法。
- 第一句表示按照id查询。
- 第二句是根据年龄查询数据,然后筛选出前十条数据作为结果返回,注意这里的排序规则是默认的ASC,按照id排序,如果需要指定具体的排序规则,可以通过OrderBy实现。
- 第三句是通过条件查询,多个条件字段用And连接,当然不仅限于And,Or也是可以的,根据实际的需要来即可。
这三句已经大概可以了解find…By…的使用,当然这里可以使用的情况很多。可以通过debug日志看具体生成的SQL语句是什么样的,这里就不去展示了。
注意:这里的参数匹配是通过参数的位置来自动匹配的,如By后面有三个条件,那么对应的就是三个参数,且按照顺序匹配,不需要使用@Param
注解指定参数的名称。(具体可看最后总结的分析)
OrderBy
排序在查询的时候经常会用到,使用起来也不是很难,可以支持多个字段的排序,并指定正序和倒序排列。
List<User> findAllOrderByAgeDescAndIdAsc();
通过这一个方法就可以了解OrderBy的写法,首先指定按照age倒序排序,如果age相同使用id正序排序。这个不难理解,多个条件会写,单个条件也不在话下了。
Like、NotLike、StartingWith、EndingWith和Containing
模糊查询,肯定会用到的,直接看实现的代码示例:
List<User> findByUserNameLike(String userName);//1
List<User> findByUserNameNotLike(String userName);//2
List<User> findByUserNameStartingWith(String userName);//3
List<User> findByUserNameEndingWith(String userName);//4
List<User> findByUserNameContaining(String userName);//5
- 1:表示按照userName字段模糊查询,会自动加上like关键字,但是不会在userName对应的值上面添加
%
或者_
,需要在传入值的时候,手动将占位符和实际值组装起来; - 2:会自动加上not like关键字,占位符需要自己手动添加;
- 3:自动加上like关键字,这里不需要手动添加占位符,会自动在字段值的前面加上
%
,转换后:like '%Joker'
; - 4:和第三句差不多,差别就是占位符
%
放置的位置调整,放在了字段值的后面; - 5:相当于第三句和第四句的综合,会在字段值的前后加上占位符
%
。
下面的列表喜欢吗
上面随机列举了几个经常使用用的查询方式,实际上还是有很多的,另外除了find开头的方式,还可以用get开头。看下面面的列表:
关键字 | 方法命名 | sql where字句 |
---|---|---|
And | findByNameAndPwd | where name = ? and pwd= ? |
Or | findByNameOrSex | where name = ? or sex =? |
Between | findByIdBetween | where id between ? and ? |
LessThan | findByIdLessThan | where id <? |
LessThanEqual | findByIdLessThanEqual | where id <=? |
GreaterThan | findByIdGreaterThan | where id > ? |
GreaterThanEqual | findByIdGreaterThanEqual | where id >= ? |
After | findByIdAfter | where id > ? |
Before | find ByIdBefore | where id < ? |
IsNull | findByNameIsNull | where name is null |
IsNotNull,NotNull | findByNameIsNotNull findByNameNotNull |
where name is not null |
Like | findByNameLike | where name like ? |
NotLike | findByNameNotLike | where name not like ? |
StartingWith | findByNameStartingWith | where name like '?%' |
EndingWith | findByNameEndingWith | where name like '%?' |
Containing | findByNameContaining | where name like '%?%' |
OrderBy | findByIdOrderByAgeDescAndIdAsc | where id = ? order by age desc,id asc |
Not | findByNameNot | where name <> ? |
In | findByNameIn | where name in (?) |
NotIn | findByIdNotIn | where id not in (?) |
True | findByDelStatusTrue | where delStatus = true |
False | findByDelStatusFalse | where delStatus = false |
IgnoreCase | findByNameIgnoreCase | where UPPER(name) = UPPER(?) |
get开头的方法就不单独写了,如果习惯使用get开头,替换掉find即可。
看到这里就知道,这些自动生成的SQL都是只支持查询,且是单表、非复杂SQL语句的实现。如果涉及到条件太多,很可能一个方法名能够占一行。
总结
整个JPA的基于方法名使用就这么多了,至于怎么取融汇贯通就看自己的造诣了。其实并不难。下面以一个例子结束这篇博客。
示例代码:
SQL语句
select *
from t_user
where
user_name like '%er'
and id >=100
and (age between 20 and 35)
order by age DESC,id ASC
方法定义
List<User> findByUserNameLikeAndIdGreaterThanEqualAndAgeBetweenOrderByAgeDescAndIdAsc(String userName,Long id,Integer startAge,Integer endAge);
说明:userName、id分别匹配前面两个参数,由于age是between范围查询,是在两个值之间,需要对应到两个参数。所以做种的参数是四个,且位置要按照顺序传入,不能错位。
方法名是不是巨长、巨牛,想要更长,就看你的脑洞啦!
本文作者:程序猿杨鲍
版权归作者所有,转载请注明出处