Spring Data JPA 查询
Spring Data的核心接口是Repository。我们来看一下最基本的CrudRepository
接口:
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> { <S extends T> S save(S entity); T findOne(ID primaryKey); Iterable<T> findAll(); Long count(); void delete(T entity); boolean exists(ID primaryKey); // … 其他的省略 }
他们的作用显而易见,分别是保存、查找、全部、数量、删除和判断是否存在 。
其他的接口,比如JpaRepository
和MongoRepository 都是定向扩展了的,都继承自CrudRepository接口。还有一个 PagingAndSortingRepository接口
增加了分页功能:
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> { Iterable<T> findAll(Sort sort); Page<T> findAll(Pageable pageable); }
如果想要访问第二页的10个,可以这样做:
PagingAndSortingRepository<User, Long> repository = … Page<User> users = repository.findAll(new PageRequest(1, 10));
注意参数的值。
要使用我们自己编写的Repository,需要在SPring中启动它:
import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @EnableJpaRepositories class Config {}
这里没有指定包名,所以根据类判断默认包。如果需要修改,可以传入参数:
@EnableJpaRepositories(basePackages={"com.pretty.awsome"})
传入一个不需要使用大括号(也不用参数名),多个可以使用数组。
然后获取实例:
public class SomeClient { @Autowired private MyRepository repository; }
对于创建查询,Spring Data 使用了一个“约定”模式:使用By、And、Or、Distinct、IgnoreCase、OrderBy等。比如
public interface CityRepository extends Repository<City, Long> { Page<City> findAll(Pageable pageable); City findByNameAndStateAllIgnoringCase(String name, String state); }
我们定义了一个City实体,有两个属性: name 和state。对于方法findByNameAndStateAllIgnoringCase必需使用这样的名字,如果改成诸如
findByNameAndCountryAllIgnoringCase
这样就会报错,说找不到country属性。
下面列一些模式:
public interface PersonRepository extends Repository<User, Long> { List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname); List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname); List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname); List<Person> findByLastnameIgnoreCase(String lastname); List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname); List<Person> findByLastnameOrderByFirstnameAsc(String lastname); List<Person> findByLastnameOrderByFirstnameDesc(String lastname); List<Person> findByAddressZipCode(ZipCode zipCode); }
最下面一个是级联查询,返回的是满足x.address.zipCode==zipCode的Person List。算法会首先查询是否有addressZipCode属性,发现没有,于是从右边开始根据驼峰进行拆分(变成了addressZip和code)发现也没有,于是移动拆分点,匹配成功。(是不是很蛋疼?不过熟练的话真的很好啊)
好了我们继续往下走,好吧?等等,好像还有问题:如果Person真的有addressZip属性怎么办(我们的目的却没变,还是根据zipCode查找),他会说“天哪找不到code属性,你丫写错了肯定”。这时候可以(而且建议)使用下划线:
List<Person> findByAddress_ZipCode(ZipCode zipCode);
所以我们在属性命名的时候要用驼峰而不是下划线。
现在我们使用limit查询,主演是First和Top:
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);
是不是很神奇(Page和Slice的区别就像List和Iterator,所以量大的时候用Slice).
我正在学习中,对一些概念也不太了解。大家有新见解请留言,有疑问可以参考http://docs.spring.io/spring-data/data-commons/docs/1.11.0.RELEASE/reference/html/
推荐阅读
-
序列化表单为json对象,datagrid带额外参提交一次查询 后台用Spring data JPA 实现带条件的分页查询 多表关联查询
-
spring data jpa碰到的坑
-
使用Spring Data JPA进行数据分页与排序
-
JPA的多表复杂查询
-
详解Spring data 定义默认时间与日期的实例
-
spring-data-jpa实现增删改查以及分页操作方法
-
详解Spring Data JPA使用@Query注解(Using @Query)
-
Spring Data JPA使用Sort进行排序(Using Sort)
-
详解Spring Data JPA系列之投影(Projection)的用法
-
详解spring boot jpa整合QueryDSL来简化复杂操作