转:Spring Data Repository有趣的定义query方法

 

原文地址: http://blog.csdn.net/youngsend/article/details/51832581

学习了Spring的一个小tutorial: Accessing Data with GemFire。我们为自定义的数据对象建立Repository,作为管理数据对象的接口。通常,我们继承Spring框架的CrudRepository接口,它为我们的Repository提供了基本的CRUD(增删改查)功能。 
自定义的Repository如下:

public interface PersonRepository extends CrudRepository<Person, String> {
    //The repository proxy can understand what "findByName", 
    //"findByAgeGreaterThan", "findByAgeLessThan",etc. mean!
    Person findByName(String name);
    Iterable<Person> findByAgeGreaterThan(int age);
    Iterable<Person> findByAgeLessThan(int age);
    Iterable<Person> findByAgeGreaterThanAndAgeLessThan(int age1, int age2);
}

非常有趣的地方在于,以上就是我们要定义的全部了!定义一个Repository接口,写上几个接口方法名,然后,你就能使用这些接口方法了!下面就讲讲Spring Data Repository怎么样根据方法名来生成query的!

以下都是参考的Spring Data JPA - Reference Documentation中的4.4 Defining Query Methods

例一:

public interface PersonRepository extends Repository<User, Long> {
  //Spring会把find…By, read…By, query…By, count…By和get…By这些前缀去掉,而只处理之后的字符串。例如,以下方法名,在Spring看来,就是EmailAddressAndLastname而已。
  //而And和Or都被作为保留关键字,并起到SQL中AND和OR的作用。
  //当然,你定义的Person对象,必须含有emailAddress和lastname属性,否则Spring找不到这些属性就会出错。
  List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

  // Enables the distinct flag for the query
  //在find和By之间可以使用Distinct关键词。
  List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
  List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

  //忽略大小写要放在最后,IgnoreCase和AllIgnoreCase
  // Enabling ignoring case for an individual property
  List<Person> findByLastnameIgnoreCase(String lastname);
  // Enabling ignoring case for all suitable properties
  List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

  // Enabling static ORDER BY for a query
  List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
  List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}

以上可以看到,SQL中的AND, OR, ASC, DESC, ORDER BY, IGNORE CASE, ALL IGNORE CASE, DISTINCT都可用。

例二

/如果Person有Address属性,而Address有ZipCode属性,那么以下方法名仍能生成你心里想着的query。过程如下:
//1.Spring在Person里找AddressZipCode属性,没找到
//2.Spring按驼峰从右往左分割,第一次,它分割为AddressZip和Code,但还是没找到AddressZip属性。
//3.Spring将分割点左移,分割为Address和ZipCode,它在Person找到了Address属性,又在Address中找到了ZipCode属性,成功。
List<Person> findByAddressZipCode(ZipCode zipCode);
//以上仍可能出错,例如Person有Address,AddressZip属性,而Address有ZipCode属性,AddressZip没有Code属性,那么Spring匹配进AddressZip里边,结果没找到Code,就失败。
//更好的方法是用下划线,下划线被Spring保留为分隔符,Address_ZipCode直接被分割成Address和ZipCode,绝不会被分割成Address_Zip和Code。
//既然如此,也要求我们在定义Person,Address类时,属性名不要使用下划线,而使用纯正的驼峰命名。
List<Person> findByAddress_ZipCode(ZipCode zipCode);

例三

Page<User> findByLastname(String lastname, Pageable pageable);

Slice<User> findByLastname(String lastname, Pageable pageable);

List<User> findByLastname(String lastname, Sort sort);

List<User> findByLastname(String lastname, Pageable pageable);

由于我不完全懂Pageable在此的用法,所以只能直译一段原文说明: 
第一个方法允许你向query方法中传入一个org.springframework.data.domain.Pageable实例,以动态地向你静态定义的query中添加分页(paging)。一个Page知道available的元素和业的总数。它能做到,是通过infrastructure生成一个计数query,来计算总数。基于所用的存储,这可能成本高,此时可以使用Slice。Slice只知道是不是有下一个Slice,这在遍历一个大结果集时已足够。 
不过在返回List时使用Sort和Pageable的区别我暂不清楚。 
返回Page接口Slice接口、List三种接口有哪些显著的利弊呢?这里只介绍一下三者的关系吧:

Slice继承了Iterable,Page继承了Slice。 
Slice: A slice of data that indicates whether there’s a next or previous slice available. Allows to obtain a Pageable to request a previous or next Slice. 
Page: A page is a sublist of a list of objects. It allows gain information about the position of it in the containing entire list. 
Page有三个新方法,getTotalElements()返回元素总数,getTotalPages()返回总页数。可以感到,Page像是个容器,而Slice像只是个迭代器。

例四:

//Frist和Top是一个意思,如果不填数字,就是1
//虽然OrderBy里也有By,但Spring只找到第一个By,然后去掉
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);

Slice<User> findTop3ByLastname(String lastname, Pageable pageable);

List<User> findFirst10ByLastname(String lastname, Sort sort);

List<User> findTop10ByLastname(String lastname, Pageable pageable);

例五

@Async
Future<User> findByFirstname(String firstname);               1

@Async
CompletableFuture<User> findOneByFirstname(String firstname); 2

@Async
ListenableFuture<User> findOneByLastname(String lastname); 

哈!多线程中。Spring的Repository query有异步执行的能力。 此时,query方法被调用后会立刻返回,但是实际的query执行发生在一个Spring TaskExecutor里,此query任务已被提交给它。一个Spring TaskExecutor么,就是一个线程。

学习了Spring的一个小tutorial: Accessing Data with GemFire。我们为自定义的数据对象建立Repository,作为管理数据对象的接口。通常,我们继承Spring框架的CrudRepository接口,它为我们的Repository提供了基本的CRUD(增删改查)功能。 
自定义的Repository如下:

public interface PersonRepository extends CrudRepository<Person, String> {
    //The repository proxy can understand what "findByName", 
    //"findByAgeGreaterThan", "findByAgeLessThan",etc. mean!
    Person findByName(String name);
    Iterable<Person> findByAgeGreaterThan(int age);
    Iterable<Person> findByAgeLessThan(int age);
    Iterable<Person> findByAgeGreaterThanAndAgeLessThan(int age1, int age2);
}

 

非常有趣的地方在于,以上就是我们要定义的全部了!定义一个Repository接口,写上几个接口方法名,然后,你就能使用这些接口方法了!下面就讲讲Spring Data Repository怎么样根据方法名来生成query的!

以下都是参考的Spring Data JPA - Reference Documentation中的4.4 Defining Query Methods

例一:

public interface PersonRepository extends Repository<User, Long> {
  //Spring会把find…By, read…By, query…By, count…By和get…By这些前缀去掉,而只处理之后的字符串。例如,以下方法名,在Spring看来,就是EmailAddressAndLastname而已。
  //而And和Or都被作为保留关键字,并起到SQL中AND和OR的作用。
  //当然,你定义的Person对象,必须含有emailAddress和lastname属性,否则Spring找不到这些属性就会出错。
  List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

  // Enables the distinct flag for the query
  //在find和By之间可以使用Distinct关键词。
  List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
  List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

  //忽略大小写要放在最后,IgnoreCase和AllIgnoreCase
  // Enabling ignoring case for an individual property
  List<Person> findByLastnameIgnoreCase(String lastname);
  // Enabling ignoring case for all suitable properties
  List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

  // Enabling static ORDER BY for a query
  List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
  List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}

124峰从右往左分割,第一次,它分割为AddressZip和Code,但还是没找到AddressZip属性。

//3.Spring将分割点左移,分割为Address和ZipCode,它在Person找到了Address属性,又在Address中找到了ZipCode属性,成功。
List<Person> findByAddressZipCode(ZipCode zipCode);
//以上仍可能出错,例如Person有Address,AddressZip属性,而Address有ZipCode属性,AddressZip没有Code属性,那么Spring匹配进AddressZip里边,结果没找到Code,就失败。
//更好的方法是用下划线,下划线被Spring保留为分隔符,Address_ZipCode直接被分割成Address和ZipCode,绝不会被分割成Address_Zip和Code。
//既然如此,也要求我们在定义Person,Address类时,属性名不要使用下划线,而使用纯正的驼峰命名。
List<Person> findByAddress_ZipCode(ZipCode zipCode);
  • 立刻返回,但是实际的query执行发生在一个Spring TaskExecutor里,此query任务已被提交给它。一个Spring TaskExecutor么,就是一个线程。

 

posted @ 2017-10-08 22:20  依米熊  阅读(720)  评论(0编辑  收藏  举报