转: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么,就是一个线程。