spring-data-JPArepository⾃定义⽅法规则
⼀、⾃定义⽅法的规则
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 =?和年龄=?和性=?
long spring是什么意思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层的⽅法上添加事务操作。 

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。