纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

JPA Repository existsBy查询失效 Spring Boot JPA Repository之existsBy查询方法失效的解决

bladestone   2021-06-10 我要评论
想了解Spring Boot JPA Repository之existsBy查询方法失效的解决的相关内容吗bladestone在本文为您仔细讲解JPA Repository existsBy查询失效的相关知识和一些Code实例欢迎阅读和指正我们先划重点:SpringBoot,JPA,Repository,existsBy查询失效下面大家一起来学习吧

引言: Spring Boot号称微服务的利器在结合了Spring Data与JPA之后更是如虎添翼开发快速的不像话本文将讲述一个关于JPA中一个诡异问题的诊断分析过程以及修复方法

环境介绍

JDK 1.8 Spring 4.2 Spring Boot 1.5.9

问题描述

在Spring Data中的Repository接口中创建了一个检查数据是否存在的接口方法:

@Repository
public interface VideoEntityRepository extends JpaRepository<VideoEntity, Long> {
    ........
    public boolean existsByUserIdAndName(long userId, String name);
   }

VideoEntity的类如下:

@SuppressWarnings("serial")
@Table(name="flook_video")
@Entity
@Data
@EqualsAndHashCode(callSuper=true)
public class VideoEntity extends BaseEntity {
    @Column(name="user_id")
    private long userId;
    @Column(name="name")
    private String name;
    @Column(name="change_version")
    private double changeVersion;
}

在调用方法existsBy方法的时候返回的结果一直为false 结果不正确在偶的期望中其执行结果应该不会出错的?那问题出在哪里呢?

关于existsBy的介绍

Spring Data提供了若干非常实用的扩展将数据库表日常的CRUD操作都进行很好的实现并提供了若干扩展机制基于一套简单易用的命名规则来基于声明式实现场景的数据库查询操作:

countByColumName
existsByColumnName

上述两种方式都是由Spring Data来帮助动态生成SQL的

基于@Query方式

除了基于countBy/existsBy两种方式之外可以直接使用@Query方式来标注特定的SQL或者JPQL来实现功能由于这种方式需要些SQL功能上完全覆盖但是工作量略大不是最优的方式

问题分析

由于底层使用了Hibernate/JPA/Spring Data来实现的数据访问层的实现所以最好的方式当然是查看动态生成的SQL了于是找到了生成的SQL语句:

select videoentit0_.id as col_0_0_ from video videoentit0_ where videoentit0_.user_id=? and videoentit0_.name=? limit ?

表的名称是video这个名称是不对的这个情况是怎么发生的呢?

问题的解决

经过分析发现是由于在代码中存在两个类名完全相同VideoEntity的类虽然在Repository中我们的的确确没有引用错误相关的问题应该出在当Spring Data碰到两个相同的类名之时其实不知道如何来生成SQL的换句话说其应该是基于类名而非类路径来动态生成执行SQL的

TODO: 基于源代码中找到相关部分内容

问题解决

将当前的VideoEntity重新命名确保不存在重名的问题即使类的路径不一样但是类名一样也是会产生这样的问题

从一个侧面来分析在Spring Data中所有的DataBean都是需要使用全路径的类名的否则同样会出现问题

JpaRepository 查询规范

1.JpaRepository支持接口规范方法名查询

意思是如果在接口中定义的查询方法符合它的命名规则就可以不用写实现目前支持的关键字如下

Keyword

Sample

JPQL snippet

IsNotNull

findByAgeNotNull

... where x.age not null

Like

findByNameLike

... where x.name like ?1

NotLike

findByNameNotLike

... where x.name not like ?1

StartingWith

findByNameStartingWith

... where x.name like ?1(parameter bound with appended %)

EndingWith

findByNameEndingWith

... where x.name like ?1(parameter bound with prepended %)

Containing

findByNameContaining

... where x.name like ?1(parameter bound wrapped in %)

OrderBy

findByAgeOrderByName

... where x.age = ?1 order by x.name desc

Not

findByNameNot

... where x.name <> ?1

In

findByAgeIn

... where x.age in ?1

NotIn

findByAgeNotIn

... where x.age not in ?1

True

findByActiveTrue

... where x.avtive = true

Flase

findByActiveFalse

... where x.active = false

And

findByNameAndAge

... where x.name = ?1 and x.age = ?2

Or

findByNameOrAge

... where x.name = ?1 or x.age = ?2

Between

findBtAgeBetween

... where x.age between ?1 and ?2

LessThan

findByAgeLessThan

... where x.age < ?1

GreaterThan

findByAgeGreaterThan

... where x.age > ?1

After/Before

...

...

IsNull

findByAgeIsNull

... where x.age is null

2.JpaRepository相关查询功能

a.Spring DataJPA框架在进行方法名解析时会先把方法名多余的前缀截取掉比如find、findBy、read、readBy、get、getBy然后对剩下部分进行解析

b.假如创建如下的查询:findByUserDepUuid()框架在解析该方法时首先剔除findBy然后对剩下的属性进行解析假设查询实体为Doc

1:先判断userDepUuid (根据POJO规范首字母变为小写)是否为查询实体的一个属性如果是则表示根据该属性进行查询如果没有该属性继续第二步

2:从右往左截取第一个大写字母开头的字符串此处为Uuid)然后检查剩下的字符串是否为查询实体的一个属性如果是则表示根据该属性进行查询如果没有该属性则重复第二步继续从右往左截取最后假设user为查询实体的一个属性

3:接着处理剩下部分(DepUuid)先判断user所对应的类型是否有depUuid属性如果有则表示该方法最终是根据“Doc.user.depUuid” 的取值进行查询否则继续按照步骤2的规则从右往左截取最终表示根据“Doc.user.dep.uuid” 的值进行查询

4:可能会存在一种特殊情况比如Doc包含一个user的属性也有一个userDep 属性此时会存在混淆可以明确在属性之间加上"_"以显式表达意图比如"findByUser_DepUuid()"或者"findByUserDep_uuid()"

c.特殊的参数: 还可以直接在方法的参数上加入分页或排序的参数比如:

Page<UserModel>findByName(String name, Pageable pageable);
List<UserModel>findByName(String name, Sort sort);

d.也可以使用JPA的NamedQueries方法如下:

1:在实体类上使用@NamedQuery:

@NamedQuery(name ="UserModel.findByAge",query = "select o from UserModel
o where o.age >=?1")

2:在自己实现的DAO的Repository接口里面定义一个同名的方法示例如下:

publicList<UserModel> findByAge(int age);

3:然后就可以使用了Spring会先找是否有同名的NamedQuery如果有那么就不会按照接口定义的方法来解析

e.还可以使用@Query来指定本地查询只要设置nativeQuery为true比如:

@Query(value="select* from tbl_user where name like %?1" ,nativeQuery=true)
publicList<UserModel> findByUuidOrAge(String name);

注意:当前版本的本地查询不支持翻页和动态的排序

f.使用命名化参数使用@Param即可比如:

@Query(value="selecto from UserModel o where o.name like %:nn")
publicList<UserModel> findByUuidOrAge(@Param("nn") String name);

g.同样支持更新类的Query语句添加@Modifying即可比如:

@Modifying
@Query(value="updateUserModel o set o.name=:newName where o.name like %:nn")
public intfindByUuidOrAge(@Param("nn") String name,@Param("newName")String
newName);

注意:

1:方法的返回值应该是int表示更新语句所影响的行数

2:在调用的地方必须加事务没有事务不能正常执行

f.创建查询的顺序

Spring Data JPA在为接口创建代理对象时如果发现同时存在多种上述情况可用它该优先采用哪种策略呢?

<jpa:repositories>提供了query-lookup-strategy 属性用以指定查找的顺序

它有如下三个取值:

1:create-if-not-found:如果方法通过@Query指定了查询语句则使用该语句实现查询如果没有则查找是否定义了符合条件的命名查询如果找到则使用该命名查询如果两者都没有找到则通过解析方法名字来创建查询这是querylookup-strategy 属性的默认值

2:create:通过解析方法名字来创建查询即使有符合的命名查询或者方法通过

@Query指定的查询语句都将会被忽略

3:use-declared-query:如果方法通过@Query指定了查询语句则使用该语句实现查询如果没有则查找是否定义了符合条件的命名查询如果找到则使用该命名查询如果两者都没有找到则抛出异常

以上为个人经验希望能给大家一个参考也希望大家多多支持


相关文章

猜您喜欢

  • hashMap死循环 hashMap扩容时应该注意这些死循环问题

    想了解hashMap扩容时应该注意这些死循环问题的相关内容吗攻城狮numberOne在本文为您仔细讲解hashMap死循环的相关知识和一些Code实例欢迎阅读和指正我们先划重点:hashMap死循环问题,hashMap扩容下面大家一起来学习吧..
  • PyQt5 文件打开保存 Python3中PyQt5简单实现文件打开及保存

    想了解Python3中PyQt5简单实现文件打开及保存的相关内容吗LOONGV在本文为您仔细讲解PyQt5 文件打开保存的相关知识和一些Code实例欢迎阅读和指正我们先划重点:PyQt5,文件打开保存下面大家一起来学习吧..

网友评论

Copyright 2020 www.fresh-weather.com 【世纪下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式