Spring Data JPA使用必备(二):Spring Data JPA方法命名规则实现SQL自动生成

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范围查询,是在两个值之间,需要对应到两个参数。所以做种的参数是四个,且位置要按照顺序传入,不能错位。

方法名是不是巨长、巨牛,想要更长,就看你的脑洞啦!

本文作者:程序猿杨鲍
版权归作者所有,转载请注明出处

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容