您的位置:首页 > 编程语言 > Java开发

Spring Data Repository有趣的定义query方法

2016-07-05 16:20 537 查看
学习了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