我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何理解Spring Data JPA查询方式及方法名查询规则

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何理解Spring Data JPA查询方式及方法名查询规则

这篇文章给大家介绍如何理解Spring Data JPA查询方式及方法名查询规则,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

Spring Data JPA查询方式及方法名查询规则

Spring Data JPA

一、通过解析方法名创建查询

在执行查询时,Spring Data JPA框架会把方法名进行解析,解析到前缀比如 get、getBy、find、findBy、read、readBy时,会先把这些前缀截取掉,然后对剩下部分进行解析,剩下部分分为两种:一是只有属性名,二是属性名+条件;条件很好解析,解析的关键在于属性名,下面拿一个具体的例子来帮助大家更好的理解属性名解析规则。

解析规则例子:比如实体为Product,方法为findByGoodsTypeDetail ();

首先截取掉 findBy,然后对剩下的属性进行解析;

先判断 goodsTypeDetail(根据 POJO 规范,首字母变为小写,下同)是否为 Product的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,继续第三步;

从右往左截取第一个大写字母开头的字符串(本方法为 Detail),然后对比剩下的字符串(本方法为goodsType)是否为 Product的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,则重复第三步,继续从右往左截取(此处为TypeDetail,剩下goods),就这样一直循环到最终;假设 goods为 Product的一个属性,则说明goods不是常量类型,而是一个对象类型;

此时剩下字符串 TypeDetail,先判断goods对象中是否有 typeDetail属性,如果有,则表示该方法最终是根据 "Product.goods.typeDetail" 的值进行查询;如果没有该属性,则继续按照第三步的规则从右往左截取,最终表示根据 "Product.goods.type.detail" 的值进行查询。

不过这种解析规则不是完美的,也存在bug,不注意可能会掉到这个坑里,比如Product中有一个属性叫goods,同时还有一个属性叫goodsType,这时在解析时会出现混乱,不过可以在属性之间加上 "_"来解决这个问题,注意:"_"是加在查询方法上的,不是加在属性名上的;比如 "findByGoods_TypeDetail()" (当Product中不存在goods_TypeDetail时,是给解析器说明Goods为一个对象)或"findByGoodsType_Detail()"(当Product中不存在goodsType_Detail时,是给解析器说明GoodsType为一个对象)。

查询时,很多时候需要同时使用多个属性进行查询,而且查询的条件也各不相同,Spring Data JPA 为此提供了一些条件查询的关键字,我把常用的都整理了一下,如下表:

关键字

对应SQL关键字

示例

列名

根据列名查询

findByName(String name);自动解析findBy后面的列名,然后根据列名查询。

In

等价于SQL 中的 in

findByNameIn(Collection<String> nameList) ;参数可以是集合、数组、不定长参数;

Like

等价于SQL 中的 like

findByNameLike(String name);

NotLike等价于SQL 中的 not likefindByNameNotLike(String name);

And

等价于SQL 中的 and

findByNameAndPwd(String name, String pwd);

Or

等价于SQL 中的 or

findByIdOrCode(String id, String code);

Between

等价于SQL 中的 between

findByNumBetween(int max, int min);

OrderBy

等价于SQL 中的 order by

findByNameOrderByNumAsc(String name);

IsNull

等价于SQL 中的 is null

findByNameIsNull();

IsNotNull等价于SQL 中的 is not nullfindByNameIsNotNull();
NotNull等价于SQL 中的 is not nullfindByNameNotNull();--和IsNotNull 一样,建议使用IsNotNull
Not等价于SQL 中的 ! =findByNameNot(String name);
NotIn等价于SQL 中的 not infindByNameNotIn(Collection<String> nameList) ;参数可以是集合、数组、不定长参数;
LessThan等价于SQL 中的 <findByNumLessThan(int num);

GreaterThan

等价于SQL 中的 >

findByNumGreaterThan(int num);

二、使用 @Query 创建查询

使用 @Query 提供的位置编号查询:格式为":位置编号",然后方法中的参数按 JPQL 查询语句的位置编号顺序书写。 如下:

public interface ProductDao extends Repository<Product , Long> {  @Query("select * from Product p where p.id= ?1") public Product findById(Long id);  @Query("select * from Product p where p.type = ?1 and p.name =?2") public Page<Product> findByTypeAndName(     Integer type,String name,Pageable pageable); }

使用@Query 命名参数查询:格式为": 变量",同时在方法的参数前面使用 @Param 将方法参数与JPQL中的命名参数对应。如下:

public interface ProductDao extends Repository<Product , Long> {  @Query("from Product p where p.goodsName= :name") public Product findByGoodsName(@Param("name")String name);  @Query("from Product p where p.num < :num") public Page<Product> findByNumLessThan(     @Param("num")Integer num,Pageable pageable); }

使用 @Modifying 将查询操作标识为更新操作:在使用 @Query 的同时使用 @Modifying ,这样会生成一个更新的操作,而非查询。如下:

 @Query("update Product p set p.name = ?1 where p.id = ?2") @Modifying public int updateName(String name, int id);

JPA 常用查询方法记录

以这张表为例:

+-------------+--------------+------+-----+-------------------+----------------+| Field       | Type         | Null | Key | Default           | Extra          |+-------------+--------------+------+-----+-------------------+----------------+| id          | int(11)      | NO   | PRI | NULL              | auto_increment || role        | varchar(45)  | NO   |     | NULL              |                || permissions | varchar(512) | NO   |     | NULL              |                || create_time | datetime     | NO   |     | CURRENT_TIMESTAMP |                || status      | varchar(45)  | NO   |     | NULL              |                || role_name   | varchar(45)  | NO   |     | NULL              |                |+-------------+--------------+------+-----+-------------------+----------------+

CrudRepository 默认带的查询方法

如何理解Spring Data JPA查询方式及方法名查询规则

@Repositorypublic interface RoleRepository extends CrudRepository<RoleData, Integer> {}  @Entity@Table(name = "role", catalog = "message_push")public class RoleData implements java.io.Serializable {     @Id    @GeneratedValue    private Integer id;     private String role;     private String permissions;     private Long create_time;     private Integer status; // getter setter 构造函数从略 }

简单的扩展-以字段为关键字进行查询

list<RoleData> findByXXX(xxx) 其中 XXX 对应数据库中的字段,例如:

@Repositorypublic interface RoleRepository extends CrudRepository<RoleData, Integer> {     List<RoleData> findByRole(String role);    List<RoleData> findByStatus(String status);}

还可以多字段AND 查询:

@Repositorypublic interface RoleRepository extends CrudRepository<RoleData, Integer> {     List<RoleData> findByRoleAndStatus(String role, String status);}

在 application.properties 中加入以下配置 spring.jpa.show-sql=true 可以看到SQL语句:

Hibernate: select roledata0_.id as id1_0_, roledata0_.create_time as create_t2_0_, roledata0_.permissions as permissi3_0_, roledata0_.role as role4_0_, roledata0_.status as status5_0_ from message_push.role roledata0_ where roledata0_.role=? and roledata0_.status=?

当然 or 也是可以:

List<RoleData> findByRoleOrStatus(String role, String status);

Hibernate: select roledata0_.id as id1_0_, roledata0_.create_time as create_t2_0_, roledata0_.permissions as permissi3_0_, roledata0_.role as role4_0_, roledata0_.status as status5_0_ from message_push.role roledata0_ where roledata0_.role=? or roledata0_.status=?

使用@Query 进行复杂查询

例如:

@Query(value = "select * from role where role = ?1", nativeQuery = true)List<RoleData> searchByRole(String role);

或 sql in 用法

@Query(value = "select * from role where role in (?1) and status = 'valid'", nativeQuery = true)List<RoleData> searchByRoleList(List<String> targetList);

又或 sql like 用法:

@Query(value = "select * from role where role like %?1%", nativeQuery = true)List<RoleData> searchByRole(String keyWord);

使用 Specification 进行复杂查询

先来看一下 JpaSpecificationExecutor 接口

如何理解Spring Data JPA查询方式及方法名查询规则

以 findAll(Specification<T>) 为例进行说明:

Specification<T> 可以理解为一个查询条件。findAll 以这个条件为基准进行查询,也就是我们在sql 里写的 whre xxx 转为 Specification 来写。

首先要让我们的 repository 继承 JpaSpecificationExecutor

@Repositorypublic interface RoleRepository extends CrudRepository<RoleData, Integer>, JpaSpecificationExecutor<RoleData> {

接下来,将这个查询 [ select * from role where role like '%a%' ] 转为一个简单的 Specification。

final Specification<RoleData> spec = new Specification<RoleData> () {            @Override            public Predicate toPredicate(Root<RoleData> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {                Predicate predicate = criteriaBuilder.like(root.get("role"), "%a%");                return predicate;            }        };

然后直接按如下方式调用即可:

roleRepository.findAll(spec);

Specification 里又衍生出了好几个类,分别介绍一下:

Predicate

因为我们实现 Specification 接口时,只需要实现 Predicate toPredicate() 方法。而 Specification 上文中我们当做搜索条件来理解了,那么也可以简单的把 Predicate 视为搜索条件。

CriteriaBuilder

用于构建搜索条件 Predicater 的。

回想一下SQL搜索条件怎么写

where attribute = xxwhere attribute > xx where attribute < xxwhere attribute like %xx%

注意这里有三要素:

  • attribute 搜索指定的数据库字段

  • 操作符 大于 小于 等于

  • 具体数据

CriteriaBuilder提供了一系列静态方法构建这三要素。

比如

  • CriteriaBuilder.like(数据库字段, 具体数据)

  • CriteriaBuilder.equal(数据库字段, 具体数据)

其中 数据库字段 不能直接写字符串,需要下一个工具类 Root 的 get 方法获取。

Root

root.get( String attributeName ) 参数 attributeName 就是数据库里的字段名

现在相信读者可以理解 我们刚才写的 那个完整的 Specification了。

再下来再上一个稍微复杂点的例子:

[  select * from role where role like '%a%' and (id > 11 or id < 8) ]
final Specification<RoleData> spec = new Specification<RoleData> () {            @Override            public Predicate toPredicate(Root<RoleData> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {                Predicate roleLikeaPredicate = criteriaBuilder.like(root.get("role"), "%a%");                Predicate idLessThan8Predicate = criteriaBuilder.lessThan(root.get("id"), 8);                Predicate idGreaterThan12Predicate = criteriaBuilder.greaterThan(root.get("id"), 11);                 Predicate idCombindedPredicate = criteriaBuilder.or(idLessThan8Predicate, idGreaterThan12Predicate);                Predicate predicate = criteriaBuilder.and(idCombindedPredicate, roleLikeaPredicate);                 return predicate;            }        };

其实也很简单,就是多了 criteriaBuilder.or criteriaBuilder.and 来把多个 Predicate 合成一个新的 Predicate

最后一个例子:

可以通过root.get(xx).in(List<> list) 也是可以直接返回 Predicate 的

         final Specification<RoleData> spec2 = new Specification<RoleData> () {            @Override            public Predicate toPredicate(Root<RoleData> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {                List<String> alist = new ArrayList<String>();                alist.add("admin");                Predicate predicate = root.get("role").in(alist);                return predicate;            }        };

关于如何理解Spring Data JPA查询方式及方法名查询规则就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何理解Spring Data JPA查询方式及方法名查询规则

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何理解Spring Data JPA查询方式及方法名查询规则

这篇文章给大家介绍如何理解Spring Data JPA查询方式及方法名查询规则,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Spring Data JPA查询方式及方法名查询规则Spring Data JPA一、通过
2023-06-21

使用Spring Data JPA如何实现自定义规则查询

使用Spring Data JPA如何实现自定义规则查询?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一、常用规则速查1   And    并且2   Or     或3
2023-05-31

spring data jpa怎么创建方法名进行简单查询

本文小编为大家详细介绍“spring data jpa怎么创建方法名进行简单查询”,内容详细,步骤清晰,细节处理妥当,希望这篇“spring data jpa怎么创建方法名进行简单查询”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一
2023-06-29

如何在mysql进行查询缓存及失败的解决方法

都知道函数在使用前需要弄清楚参数的属性,这样才能对函数的使用有较好的了解。有些小伙伴学习了查询缓存后,直接进行了下一步的实战操作。这里小编想提醒大家,开始操作之前一定要先设置参数,不然就会出现问题。下面我们来完整的讲一下mysql查询缓存的
2022-05-26

如何实现MySQL底层优化:查询优化器的工作原理及调优方法

如何实现MySQL底层优化:查询优化器的工作原理及调优方法在数据库应用中,查询优化是提高数据库性能的重要手段之一。MySQL作为一种常用的关系型数据库管理系统,其查询优化器的工作原理及调优方法十分重要。本文将介绍MySQL查询优化器的工作原
如何实现MySQL底层优化:查询优化器的工作原理及调优方法
2023-11-08

如何查询软考系统集成项目管理工程师考试成绩及证书领取方式

软考系统集成项目管理工程师考试是中国计算机技术与软件专业技术资格(水平)考试的一部分,考试成绩的查询和证书的领取是考生非常关心的问题。本文将详细介绍考试成绩的查询方法及证书领取的具体步骤。
如何查询软考系统集成项目管理工程师考试成绩及证书领取方式
2024-10-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录