如何理解Spring Data JPA查询方式及方法名查询规则(jpa,spring data,开发技术)

时间:2024-05-02 21:40:05 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

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

Spring Data JPA

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

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

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

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

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

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

4、此时剩下字符串 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 一样,建议使用IsNotNullNot等价于SQL 中的 ! =findByNameNot(String name);NotIn等价于SQL 中的 not infindByNameNotIn(Collection<String> nameList) ;参数可以是集合、数组、不定长参数;LessThan等价于SQL 中的 <findByNumLessThan(int num);

GreaterThan

等价于SQL 中的 >

findByNumGreaterThan(int num);

二、使用 @Query 创建查询

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

publicinterfaceProductDaoextendsRepository<Product,Long>{@Query("select*fromProductpwherep.id=?1")publicProductfindById(Longid);@Query("select*fromProductpwherep.type=?1andp.name=?2")publicPage<Product>findByTypeAndName(Integertype,Stringname,Pageablepageable);}

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

publicinterfaceProductDaoextendsRepository<Product,Long>{@Query("fromProductpwherep.goodsName=:name")publicProductfindByGoodsName(@Param("name")Stringname);@Query("fromProductpwherep.num<:num")publicPage<Product>findByNumLessThan(@Param("num")Integernum,Pageablepageable);}

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

@Query("updateProductpsetp.name=?1wherep.id=?2")@ModifyingpublicintupdateName(Stringname,intid);

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查询方式及方法名查询规则

@RepositorypublicinterfaceRoleRepositoryextendsCrudRepository<RoleData,Integer>{}@Entity@Table(name="role",catalog="message_push")publicclassRoleDataimplementsjava.io.Serializable{@Id@GeneratedValueprivateIntegerid;privateStringrole;privateStringpermissions;privateLongcreate_time;privateIntegerstatus;//gettersetter构造函数从略}

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

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

@RepositorypublicinterfaceRoleRepositoryextendsCrudRepository<RoleData,Integer>{List<RoleData>findByRole(Stringrole);List<RoleData>findByStatus(Stringstatus);}

还可以多字段AND 查询:

@RepositorypublicinterfaceRoleRepositoryextendsCrudRepository<RoleData,Integer>{List<RoleData>findByRoleAndStatus(Stringrole,Stringstatus);}

在 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(Stringrole,Stringstatus);

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*fromrolewhererole=?1",nativeQuery=true)List<RoleData>searchByRole(Stringrole);

或 sql in 用法

@Query(value="select*fromrolewhererolein(?1)andstatus='valid'",nativeQuery=true)List<RoleData>searchByRoleList(List<String>targetList);

又或 sql like 用法:

@Query(value="select*fromrolewhererolelike%?1%",nativeQuery=true)List<RoleData>searchByRole(StringkeyWord);

使用 Specification 进行复杂查询

先来看一下 JpaSpecificationExecutor 接口

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

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

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

首先要让我们的 repository 继承 JpaSpecificationExecutor

@RepositorypublicinterfaceRoleRepositoryextendsCrudRepository<RoleData,Integer>,JpaSpecificationExecutor<RoleData>{

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

finalSpecification<RoleData>spec=newSpecification<RoleData>(){@OverridepublicPredicatetoPredicate(Root<RoleData>root,CriteriaQuery<?>query,CriteriaBuildercriteriaBuilder){Predicatepredicate=criteriaBuilder.like(root.get("role"),"%a%");returnpredicate;}};

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

roleRepository.findAll(spec);

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

Predicate

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

CriteriaBuilder

用于构建搜索条件 Predicater 的。

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

whereattribute=xxwhereattribute>xxwhereattribute<xxwhereattributelike%xx%

注意这里有三要素:

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

  • 操作符 大于 小于 等于

  • 具体数据

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

比如

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

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

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

Root

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

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

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

[select*fromrolewhererolelike'%a%'and(id>11orid<8)]
finalSpecification<RoleData>spec=newSpecification<RoleData>(){@OverridepublicPredicatetoPredicate(Root<RoleData>root,CriteriaQuery<?>query,CriteriaBuildercriteriaBuilder){PredicateroleLikeaPredicate=criteriaBuilder.like(root.get("role"),"%a%");PredicateidLessThan8Predicate=criteriaBuilder.lessThan(root.get("id"),8);PredicateidGreaterThan12Predicate=criteriaBuilder.greaterThan(root.get("id"),11);PredicateidCombindedPredicate=criteriaBuilder.or(idLessThan8Predicate,idGreaterThan12Predicate);Predicatepredicate=criteriaBuilder.and(idCombindedPredicate,roleLikeaPredicate);returnpredicate;}};

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

最后一个例子:

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

finalSpecification<RoleData>spec2=newSpecification<RoleData>(){@OverridepublicPredicatetoPredicate(Root<RoleData>root,CriteriaQuery<?>query,CriteriaBuildercriteriaBuilder){List<String>alist=newArrayList<String>();alist.add("admin");Predicatepredicate=root.get("role").in(alist);returnpredicate;}};
 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:如何理解Spring Data JPA查询方式及方法名查询规则的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:如何理解node.js中Util模块作用下一篇:

2 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18