zoukankan      html  css  js  c++  java
  • spring-data-JPA repository自定义方法规则

    一、自定义方法的规则

    Spring Data JPA框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如find,findBy,read,readBy,get,getBy,然后对剩下的部分进行解析。
    假如创建如下的查询:findByUserDepUuid(),框架在解析该方法时,首先剔除findBy,然后对剩下的属性进行解析,假设查询实体为Doc
    1:先判断userDepUuid(根据POJO规范,首字母变为小写)是否为查询实体的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,继续第二步;
    2:从右往左截取第一个大写字母开头的字符串此处为UUID),然后检查剩下的字符串是否为查询实体的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,则重复第二步,继续从右往左截取;最后假设用户为查询实体的一个属性;
    3:接着处理剩下部分(DepUuid),先判断用户所对应的类型是否有depUuid属性,如果有,则表示该方法最终是根据“Doc.user.depUuid”的取值进行查询;否则继续按照步骤2的规则从右往左截取,最终表示根据“Doc.user.dep.uuid”的值进行查询。
    4:可能会存在一种特殊情况,比如Doc包含一个用户的属性,也有一个userDep属性,此时会存在混合。可以明确在属性之间加上“_”以显式表达意思,比如“findByUser_DepUuid )“或者”findByUserDep_uuid()"
    关键词    样品    JPQL片段
    IsNotNull    findByAgeNotNull    ...其中x.age 不为空【年龄不为空】
    喜欢    findByNameLike    ...其中x.name是什么样的?【模糊查找是......】
    不喜欢    findByNameNotLike    ...其中x.name不喜欢?【模糊查找不是......】
    从...开始    findByNameStartingWith    ...其中x.name类似?(参数绑定附加%)【模糊匹配,类似使用%结尾】
    EndingWith    findByNameEndingWith    ...其中x.name类似于?(参数与预置%绑定)【模糊匹配,类似使用%开始】
    含    findByNameContaining    ...其中x.name like?(参数绑定在%中)[模糊匹配,类似使用%开头和结尾]
    排序依据    findByAgeOrderByName    ...其中x.age =?order by x.name desc 【查找后排序】
    不    findByNameNot    ...其中x.name <>?【查找列不是...的】
    在    findByAgeIn    ...哪里x.age在?
    NotIn    findByAgeNotIn    ...其中x.age不在?
    真正    findByActiveTrue    ...其中x.avtive = true
    产品嫁接    findByActiveFalse    ...其中x.active = false
    和     findByNameAndAge    ...其中x.name =?和x.age =?2
    要么    findByNameOrAge    ...其中x.name =?或x.age =?2
    之间    findBtAgeBetween    ...其中x.age之间?和?2
    少于    findByAgeLessThan    ...其中x.age <?
    比...更棒    findByAgeGreaterThan    ...其中x.age>?
    在那之后    ...    ...
    一片空白    findByAgeIsNull    ...其中x.age为空

    自定义查找实例:

        /**
         * 根据id查用户
         **/
        List<User> findByIdOrName(Long id,String name);
     
        /**
         * 根据id查用户
         **/
        User queryXXXXByName(String name);
     
        /**
         * 根据id查name
         **/
        User readNameById(Long id);
     
        /**
         * 查年龄为10岁的学生
         **/
        List<User> getByAge(int age);

    三,Spring Data JPA分页查询:

        /**
         * 分页查询左右用户
         * @param pageable
         * @return
         */
        Page<User> findAll(Pageable pageable);
     
        /**
         * 分页查询id不是传入id的用户
         * @param id
         * @param pageable
         * @return
         */
        Page<User> findByIdNot(Long id,Pageable pageable);

    【注意】分页查询,的结果页,,页接口继承自切片,这个接口有以下方法

    public interface Slice<T> extends Iterable<T> {
        int getNumber();//返回当前页码
     
        int getSize();//返回当前页大小(可能不是一整页)
     
        int getNumberOfElements();//返回当前的元素数量
     
        List<T> getContent();//返回当前页的内容(查询结果)
     
        boolean hasContent();//判断是否有内容存在
     
        Sort getSort();//返回排序方式
     
        boolean isFirst();//判断是不是第一页
     
        boolean isLast();//判断是不是最后一页
     
        boolean hasNext();//判断是否还有下一页
     
        boolean hasPrevious();//判断是否上一页
     
        Pageable nextPageable();//返回下一页
     
        Pageable previousPageable();//返回上一页,如果当前已经是第一个,则返回,请求前一个可以是【null】。在调用此方法之前,客户端应该检查是否收到一个非值。
     
        <S> Slice<S> map(Converter<? super T, ? extends S> var1);//用给定的映射,映射当前的内容,为Slice
    }
    方法名    关键字    SQL
    findById         其中id =?
    findByIdIs    是    其中id =?
    findByIdEquals    等于    其中id =?
    findByNameAndAge    和    where name =?和年龄=?
    findByNameOrAge    要么    where name =?或年龄=?
    findByNameOrderByAgeDesc    按顺序排列    where name =?按年龄顺序排列
    findByAgeNotIn    不在    年龄不在(?)
    findByStatusTrue    真正    where status = true
    findByStatusFalse    假    其中status = false
    findByAgeBetween    之间    年龄在哪?和?
    findByNameNot    不    名称<>?
    findByAgeLessThan    少于    年龄<?
    findByAgeLessThanEqual    LessThanEqual    年龄<=?
    findByAgeGreaterThan    比...更棒    年龄>?
    findByAgeGreaterThanEqual    GreaterThanEqual    年龄> =?
    findByAgeAfter    后    年龄>?
    findByAgeBefore    之前    年龄<?
    findByNameIsNull    一片空白    其中名称为空
    findByNameNotNull    不为空    其中名称不为空
    findByNameLike    喜欢    哪里的名字像?
    findByNameNotLike    不喜欢    哪里的名字不像?
    findByNameStartingWith    从...开始    名称如'?%'
    findByNameEndingWith    EndingWith    名称如'%?'
    findByNameContaining    含    名称如'%?%'

    代码中几个复杂的。 
    findByNameAndAgeAndSex:表示where name =?和年龄=?和性=? 
    findByNameInAndAgeIsNull:表示(?)中的名称和年龄为null  
    findByNameAndAgeInAndSexIn:表示where name =?年龄(?)和性别(?)

    可以看出关键字是可以连用的,查找都是用findBy +表中列名,表的列名还有关键字等等拼接时,它们的首字母要大写。  

    二、懒加载引起的no-session解决方法之一,没有页面只有测试用例没有效果

     

      懒加载造成JPA提供的findOne方法和save 方法在关联表查询和保存时报错;所以适合单表操作,多表可以通过自定义方法分别执行

       保存和更新需要通过@Query的方法执行

    三、@Query注解的使用

    1. 一个使用@Query注解的简单例子

    @Query(value = "select name,author,price from Book b where b.price>?1 and b.price<?2")
    List<Book> findByPriceRange(long price1, long price2);

    2.  Like表达式

    @Query(value = "select name,author,price from Book b where b.name like %:name%")
    List<Book> findByNameMatch(@Param("name") String name);

    3. 使用Native SQL Query

    所谓本地查询,就是使用原生的sql语句(根据数据库的不同,在sql的语法或结构方面可能有所区别)进行查询数据库的操作。

    @Query(value = "select * from book b where b.name=?1", nativeQuery = true)
    List<Book> findByName(String name);

    4. 使用@Param注解注入参数

    @Query(value = "select name,author,price from Book b where b.name = :name AND b.author=:author AND b.price=:price")
    List<Book> findByNamedParam(@Param("name") String name, @Param("author") String author,
            @Param("price") long price);

    5. SPEL表达式(使用时请参考最后的补充说明)

       '#{#entityName}'值为'Book'对象对应的数据表名称(book)。

    public interface BookQueryRepositoryExample extends Repository<Book, Long>{

           @Query(value = "select * from #{#entityName} b where b.name=?1", nativeQuery = true)
           List<Book> findByName(String name);

    }

    6. 一个较完整的例子

    复制代码
    public interface BookQueryRepositoryExample extends Repository<Book, Long> {
        @Query(value = "select * from Book b where b.name=?1", nativeQuery = true) 
        List<Book> findByName(String name);// 此方法sql将会报错(java.lang.IllegalArgumentException),看出原因了吗,若没看出来,请看下一个例子
    
        @Query(value = "select name,author,price from Book b where b.price>?1 and b.price<?2")
        List<Book> findByPriceRange(long price1, long price2);
    
        @Query(value = "select name,author,price from Book b where b.name like %:name%")
        List<Book> findByNameMatch(@Param("name") String name);
    
        @Query(value = "select name,author,price from Book b where b.name = :name AND b.author=:author AND b.price=:price")
        List<Book> findByNamedParam(@Param("name") String name, @Param("author") String author,
                @Param("price") long price);
    
    }
    复制代码

    7.  解释例6中错误的原因:

         因为指定了nativeQuery = true,即使用原生的sql语句查询;否则表名需为实体类对象。使用java对象'Book'作为表名来查自然是不对的。只需将Book替换为表名book。

    @Query(value = "select * from book b where b.name=?1", nativeQuery = true)
    List<Book> findByName(String name);
    @Param入参有此注解,则sql中用:name接收参数;否则用?1的占位符接收参数且顺序也要一致

    8.   有同学提出来了,例子5中用'#{#entityName}'为啥取不到值啊?

      先来说一说'#{#entityName}'到底是个啥。从字面来看,'#{#entityName}'不就是实体类的名称么,对,他就是。

      实体类Book,使用@Entity注解后,spring会将实体类Book纳入管理。默认'#{#entityName}'的值就是'Book'。

      但是如果使用了@Entity(name = "book")来注解实体类Book,此时'#{#entityName}'的值就变成了'book'。

      只需要在用@Entity来注解实体类时指定name为此实体类对应的表名。在原生sql语句中,就可以把'#{#entityName}'来作为数据表名使用。

    9.  @Modifying注解

        1、在@Query注解中编写JPQL实现DELETE和UPDATE操作的时候必须加上@modifying注解,以通知Spring Data 这是一个DELETE或UPDATE操作。

        2、UPDATE或者DELETE操作需要使用事务,此时需要 定义Service层,在Service层的方法上添加事务操作。  

  • 相关阅读:
    ASP.NET中的特殊路径标识"~"
    ASP.NET中的Request、Response、Server对象
    XSS漏洞(跨站脚本)
    WEB开发原则
    HTTP协议
    【原】从零开始改造淘淘商城(引入dubbo解决项目耦合)02
    【转】Nginx的启动、停止与重启
    【原】spring boot添加cros全局过滤器
    【转】Swagger2 添加HTTP head参数
    【原】Spring Boot 配置swagger2没有文档解决方案
  • 原文地址:https://www.cnblogs.com/h-c-g/p/10980469.html
Copyright © 2011-2022 走看看