- Repository: 最顶层的接口,是一个空接口,目的是为了统一所有的Repository的类型,且能让组件扫描时自动识别
- CrudRepository: Repository的子接口,提供CRUD 的功能。
- PagingAndSortingRepository:CrudRepository的子接口, 添加分页排序。
- JpaRepository: PagingAndSortingRepository的子接口,增加批量操作等。
- JpaSpecificationExecutor: 用来做复杂查询的接口。
- JpaRepositoryImplementation:继承了JpaSpecificationExecutor和JpaRepository,做所有的CRUD,如果想要使用JPQL和Criteria两种查询,建议继承此接口
Repository
最顶层的接口,是一个空的接口,目的是为了统一所有Repository的类型,且能让组件扫描的时候自动识别。
CrudRepository
是Repository的子接口,提供基础的CRUD的功能。
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity); //保存
<S extends T> Iterable<S> saveAll(Iterable<S> entities);//批量保存
Optional<T> findById(ID id); //按ID查询
boolean existsById(ID id);//查询ID是否存在
Iterable<T> findAll();//查询所有
Iterable<T> findAllById(Iterable<ID> ids);//查询所有ID相同的
long count();//计算条数
void deleteById(ID id);//按ID删除
void delete(T entity);//按实体类条件删除
void deleteAll(Iterable<? extends T> entities);//按实体类 删除全部数据
void deleteAll();//删除所有数据
}
PagingAndSortingRepository
是CrudRepository的子接口,添加分页和排序的功能
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);//排序
Page<T> findAll(Pageable pageable);//分页
}
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
List<T> findAll();
List<T> findAll(Sort sort);
List<T> findAllById(Iterable<ID> ids);
<S extends T> List<S> saveAll(Iterable<S> entities);
void flush();
<S extends T> S saveAndFlush(S entity);
void deleteInBatch(Iterable<T> entities);
void deleteAllInBatch();
T getOne(ID id);
@Override
<S extends T> List<S> findAll(Example<S> example);
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
}
public interface JpaSpecificationExecutor<T> {
Optional<T> findOne(@Nullable Specification<T> spec);
List<T> findAll(@Nullable Specification<T> spec);
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);
List<T> findAll(@Nullable Specification<T> spec, Sort sort);
long count(@Nullable Specification<T> spec);
}
JpaRepositoryImplementation(最佳版本):继承了JpaSpecificationExecutor和JpaRepository,做所有的CRUD,如果想要使用JPQL和Criteria两种查询,建议继承此接口
SimpleJpaRepository:是上面接口的实现类,负责规范化查询语句,里面有EntityManager
public interface UserDao extends JpaRepository<对应的Entity类, 该类的主键类型>{...}
<S extends T> S save(S entity);
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
Optional<T> findById(ID id);
boolean existsById(ID id);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> ids);
long count();
void deleteById(ID id);
void delete(T entity);
void deleteAll(Iterable<? extends T> entities);
void deleteAll();
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
List<T> findAll();
List<T> findAll(Sort sort);
List<T> findAllById(Iterable<ID> ids);
<S extends T> List<S> saveAll(Iterable<S> entities);
void flush();
<S extends T> S saveAndFlush(S entity);
void deleteInBatch(Iterable<T> entities);
void deleteAllInBatch();
T getOne(ID id);
<S extends T> List<S> findAll(Example<S> example);
<S extends T> List<S> findAll(Example<S> example, Sort sort);
public interface UserRepository extends JpaRepository<User, Long>{...}
public interface UserRepository extends JpaRepository<User, Long>{
//按照用户名模糊查询,username是User类的一个字段
findByUsernameLike(String username);
}
标准化查询对应的JPQL语法
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1(parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1(parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1(parameter bound wrapped in%) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
True | findByActiveTrue() | … where x.active = true |
False | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
- @Query(“原生的SQL语句”)
- @Query(value=“原生的SQL语句”)
方式一:使用 ?1、?2 … 占位符从一开始
@Query("SELECT p FROM Person p WHERE name LIKE %?1% AND sex=?2")
Person findByNameLikeAndSexIs(String name,Integer sex);//注意要按顺序s
方式二:Sql语句使用 :param ,并且在方法形参使用注解 @Param(“param”) 注意注解中的值要与Sql中的 :param 一致
@Query("SELECT p FROM Person p WHERE name LIKE %:name% AND sex=:sex")
Person findByNameLikeAndSexIs(@Param("sex")Integer sexInt,@Param("name")String nameStr);//可以不按顺序
public interface UserRepository extends JpaRepository<User, Long> {
//第一种传参方式;另外,在JPQL语法中,User只的不是表而是User实体类
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
//第二种传参方式
@Query("select u from User u where u.firstname like %:firstname")
List<User> findByFirstnameEndsWith(@Param("firstname")String firstname);
//使用了原生Sql语句查询
@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
//原生语句的分页条件查询,Page需要两个对象,因此由两条语句:一个负责结果,一个负责总数
@Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",nativeQuery = true)
Page<User> findByLastname(String lastname, Pageable pageable);
//更新语句,一定要用@Modifying声明,在service层一定要使用事务@Transactional,要不会报错
@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);
}
@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
Spring-data-jpa 的@modifying注解
@Modifying
进行标注,作用:提示 JPA 该操作是修改操作@Transactional
//更新语句,一定要用@Modifying声明,在service层一定要使用事务@Transactional,要不会报错
@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);
//1.当进行 find 操作时,JPA 在 EntityManager 中缓存了 find 生成的对象,当再次 find 时会直接返回该对象。于是可能会出现下面这种情况 用 @Query 定义一个修改状态的方法
public interface EntityRepository extends JpaRepository<Entity, Integer> {
@Modifying
@Query("update Entity set status = 'IGNORED' where id = ?1")
int updateStatus(int id);
}
//2.先读取一个对象,再修改对象状态,再次读取对象
Optional<Entity> entityBefore = repository.findById(1);
repository.updateStatus(1);
Optional<Entity> entityAfter = repository.findById(1);
//3.结果会发现 entityBefore 和 entityAfter 中的 Entity 对象 id 是相同的,中间对状态的修改并没有体现出来!当然,其原因也很明确,@Query 跟 find 和 save 系列方法是两套不同的体系,@Query 引起的数据库变更 EntityManager 并不能发现,更进一步说,使用其它工具或者其它框架修改数据库中的数据,也不能及时反应到 JPA 的 find 系列方法上来。
//4.当然,只要有缓存机制就一定不可避免存在此类问题,这仅是个取舍问题而不要认为是 BUG。如果要解决 find 得到的值不是数据库中最新值的问题可以有几种方式,避免使用 @Query 是一种方式,在需要时显式清理 EntityManager 的缓存也是一种方式。Spring Data JPA 提供了另外一种方式则是 @Modifying(clearAutomatically = true),@Modifying 的 clearAutomatically 属性为 true 时,执行完 modifying query 之后就会清理缓存,从而在下次 find 时就可以读取到数据库中的最新值。
//5.自动清理之后还会带来一个新的问题,clear 操作清理的缓存中,还包括提交后未 flush 的数据,例如调用 save 而不是 saveAndFlush 就有可能不会立即将修改内容更新到数据库中,在 save 之后 flush 之前调用 @Modifying(clearAutomatically = true) 修饰的方法就有可能导致修改丢失。如果再要解决这个问题,还可以再加上另外一个属性 @Modifying(clearAutomatically = true, flushAutomatically = true),@Modifying 的 flushAutomatically 属性为 true 时,执行 modifying query 之前会先调用 flush 操作,从而避免数据丢失问题。
//6.在实际运行中,clear 和 flush 操作都可能需要消耗一定的时间,要根据系统实际情况可以选择使用其中的一个或两个属性,以保证系统的正确性。
当进行 find 操作时,JPA 在 EntityManager 中缓存了 find 生成的对象,当再次 find 时会直接返回该对象。于是可能会出现下面这种情况 用 @Query 定义一个修改状态的方法
先读取一个对象,再修改对象状态,再次读取对象
结果会发现 entityBefore 和 entityAfter 中的 Entity 对象 id 是相同的,中间对状态的修改并没有体现出来!当然,其原因也很明确,@Query 跟 find 和 save 系列方法是两套不同的体系,@Query 引起的数据库变更 EntityManager 并不能发现,更进一步说,使用其它工具或者其它框架修改数据库中的数据,也不能及时反应到 JPA 的 find 系列方法上来。
当然,只要有缓存机制就一定不可避免存在此类问题,这仅是个取舍问题而不要认为是 BUG。如果要解决 find 得到的值不是数据库中最新值的问题可以有几种方式,避免使用 @Query 是一种方式,在需要时显式清理 EntityManager 的缓存也是一种方式。Spring Data JPA 提供了另外一种方式则是 @Modifying(clearAutomatically = true),@Modifying 的 clearAutomatically 属性为 true 时,执行完 modifying query 之后就会清理缓存,从而在下次 find 时就可以读取到数据库中的最新值。
自动清理之后还会带来一个新的问题,clear 操作清理的缓存中,还包括提交后未 flush 的数据,例如调用 save 而不是 saveAndFlush 就有可能不会立即将修改内容更新到数据库中,在 save 之后 flush 之前调用 @Modifying(clearAutomatically = true) 修饰的方法就有可能导致修改丢失。如果再要解决这个问题,还可以再加上另外一个属性 @Modifying(clearAutomatically = true, flushAutomatically = true),@Modifying 的 flushAutomatically 属性为 true 时,执行 modifying query 之前会先调用 flush 操作,从而避免数据丢失问题。
在实际运行中,clear 和 flush 操作都可能需要消耗一定的时间,要根据系统实际情况可以选择使用其中的一个或两个属性,以保证系统的正确性。
7.1.接口关系
public interface AbstractQuery<T> extends CommonAbstractCriteria {
//最关键的是from方法,可以得到语句的条件部分根对象
<X> Root<X> from(Class<X> entityClass);
<X> Root<X> from(EntityType<X> entity);
AbstractQuery<T> where(Expression<Boolean> restriction);
AbstractQuery<T> where(Predicate... restrictions);
AbstractQuery<T> groupBy(Expression<?>... grouping);
AbstractQuery<T> groupBy(List<Expression<?>> grouping);
AbstractQuery<T> having(Expression<Boolean> restriction);
AbstractQuery<T> having(Predicate... restrictions);
AbstractQuery<T> distinct(boolean distinct);
Set<Root<?>> getRoots();
Selection<T> getSelection();
List<Expression<?>> getGroupList();
Predicate getGroupRestriction();
boolean isDistinct();
Class<T> getResultType();
}
public interface CriteriaQuery<T> extends AbstractQuery<T> {
CriteriaQuery<T> select(Selection<? extends T> selection);
CriteriaQuery<T> multiselect(Selection<?>... selections);
CriteriaQuery<T> multiselect(List<Selection<?>> selectionList);
CriteriaQuery<T> where(Expression<Boolean> restriction);//应用查询条件实例的方法
CriteriaQuery<T> where(Predicate... restrictions);//应用查询条件实例的方法
CriteriaQuery<T> groupBy(Expression<?>... grouping);
CriteriaQuery<T> groupBy(List<Expression<?>> grouping);
CriteriaQuery<T> having(Expression<Boolean> restriction);
CriteriaQuery<T> having(Predicate... restrictions);
CriteriaQuery<T> orderBy(Order... o);
CriteriaQuery<T> orderBy(List<Order> o);
CriteriaQuery<T> distinct(boolean distinct);
List<Order> getOrderList();
Set<ParameterExpression<?>> getParameters();
}
//这里列一下Expression的继承树,仅列出常见的
* Expression (定义了:isNull、isNotNull、in、as。。。)
* Predicate(定义了:not,还有枚举对象{AND,OR}。。。)
* Subquery(子查询接口,里面有select、where、groupBy、having。。。)
* Path(JPA定义的,定义了一些获取方法,有和实体相关的,有和表达式相关的)
* From(JPA定义的,定义了许多join相关的方法)
* Join(连接查询,定义了join的条件on。。。)
* Root(就一个获取实体的方法)
Specification接口:处理复杂查询,如多条件分页查询 Specification接口使用和意义
里面定义了基本的连接语句动态添加的方法,Specifications是该接口的实现类
注意方法toPredicate(断言方法),此方法负责处理criteria语句的条件,需要实现此方法
@SuppressWarnings("deprecation")
public interface Specification<T> extends Serializable {
long serialVersionUID = 1L;
static <T> Specification<T> not(Specification<T> spec) {
return Specifications.negated(spec);
}
static <T> Specification<T> where(Specification<T> spec) {
return Specifications.where(spec);
}
default Specification<T> and(Specification<T> other) {
return Specifications.composed(this, other, AND);
}
default Specification<T> or(Specification<T> other) {
return Specifications.composed(this, other, OR);
}
//上面几个方法中,Specifications是该接口的实现类,可能适用于语句的连接,方法都过期了,我没用过
@Nullable
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
//需要实现改方法,默认绑定了3个参数,root和criteriaBuilder都十分有用
/*网上看到有人这么总结(其实就是上面的参考链接~)
Root:查询哪个表
CriteriaQuery:查询哪些字段,排序是什么
CriteriaBuilder:字段之间是什么关系,如何生成一个查询条件,每一个查询条件都是什么方式
Predicate(Expression):单独每一条查询条件的详细描述*/
}
JpaSpecificationExecutor接口:是复杂查询的主要入口,传入Specification对象
这个接口里的方法全部是围绕着上面的接口Specification写的
想使用Specification对象构造复杂查询语句,Dao层需要先继承该接口,然后实现Specification的toPredicate方法。
import org.springframework.data.jpa.domain.Specification;
public interface JpaSpecificationExecutor<T> {
Optional<T> findOne(@Nullable Specification<T> spec);
List<T> findAll(@Nullable Specification<T> spec);
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);//分页,推荐使用
List<T> findAll(@Nullable Specification<T> spec, Sort sort);
long count(@Nullable Specification<T> spec);
}
@NoRepositoryBean
public interface JpaRepositoryImplementation<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {...}
7.2.Criteria 查询原理
是一种类型安全和更面向对象的查询
通过EntityManager的getCriteriaBuilder或EntityManagerFactory的getCriteriaBuilder方法可以得到CriteriaBuilder对象(该对象由hibernate提供)
通过调用CriteriaBuilder的createQuery或createTupleQuery方法可以获得CriteriaQuery的实例
通过调用CriteriaQuery的from方法(方法定义在AbstractQuery,但是由CriteriaQueryImpl实现)可以获得Root实例
过滤条件会被应用到SQL语句的FROM子句中。在criteria 查询中,查询条件通过Predicate或Expression实例应用到CriteriaQuery对象上。
这些条件使用 CriteriaQuery .where 方法应用到CriteriaQuery 对象上
CriteriaBuilder也作为Predicate实例的工厂,通过调用CriteriaBuilder 的条件方法( equal,notEqual, gt, ge,lt, le,between,like等)创建Predicate对象。
复合的Predicate 语句可以使用CriteriaBuilder的and, or andnot 方法构建
7.3.Criteria查询
使用条件
@Repository
public interface FairyAdminDao extends JpaRepositoryImplementation<FairyAdmin,Integer> {//两个参数,一个是对应的实体类,一个是该实体类主键的类型}
7.4.综合查询示例
//测试Criteria查询
public void criteriaQueryTest() {
//1.新建排序
Sort sort = Sort.by(Sort.Direction.DESC,"adminUsername");
//2.新建分页
PageRequest pageRequest = PageRequest.of(0, 5, sort);
//3.实现接口方法specification,添加条件
Specification<FairyAdmin> specification = new Specification<FairyAdmin>(){
@Override
public javax.persistence.criteria.Predicate toPredicate(Root<FairyAdmin> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//3.1.混合条件查询
Path<String> path1 = root.get("adminUsername");//注意String,一定要类型匹配
//Path path2 = root.get("adminPassword");//可以像下面直接写到参数里
Predicate predicate = cb.and(cb.like(path1, "%yoko%"),cb.like(root.get("adminPassword").as(String.class),"%456%"));
//3.2.多表查询
//Join join = root.join("catList", JoinType.INNER);
Join<FairyAdmin, FairyCat> join = root.join(root.getModel().getList("catList",FairyCat.class), JoinType.INNER);
Path<String> catName = join.get("catName");
Predicate predicate2 = cb.and(cb.like(path1, "%yoko%"),cb.like(root.get("adminPassword").as(String.class),"%456%"),cb.like(catName,"%cat1%"));
//输3.2.1出语句...inner join tab_cat c on adminId=c.admin_adminId where (adminUsername like ?) and (adminPassword like ?) and (c.catName like ?) order by adminUsername desc limit ?,?
//return predicate2;
//3.3.使用CriteriaQuery直接设置条件,不再需要返回值
query.where(predicate2);//这里可以设置任意条查询条件
return null;//这种方式使用JPA的API设置了查询条件,所以不需要再返回查询条件Predicate给Spring Data Jpa,故最后return null
}
};
//4.执行查询
List<FairyAdmin> list = fairyAdminRepository.findAll(specification, pageRequest).getContent();
//list.forEach(System.out::println);
for (FairyAdmin admin: list) {
System.out.println(admin);
System.out.println(admin.getCatList());//设置了级联关系,默认自动查询了
}
}
7.5.查询示例
/**
* 单条件查询
* 需求:根据ID查询数据
*/
@GetMapping("/select1")
public void criteriaQueryTest1() {
//3.实现接口方法specification,添加条件
Specification<FairyAdmin> specification = new Specification<FairyAdmin>(){
/**
* @return Predicate:定义了查询条件
* @param root root:根对象。封装了查询条件的对象
* @param query query:定义了一个基本的查询.一般不
使用
* @param cb cb:创建一个查询条件
*/
@Override
public javax.persistence.criteria.Predicate toPredicate(Root<FairyAdmin> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate pre = cb.equal(root.get("adminId"),4);
//3.3.使用CriteriaQuery直接设置条件,不再需要返回值
query.where(pre);//这里可以设置任意条查询条件
return null;//这种方式使用JPA的API设置了查询条件,所以不需要再返回查询条件Predicate给Spring Data Jpa,故最后return null
}
};
//4.执行查询
List<FairyAdmin> list = fairyAdminRepository.findAll(specification);
for (FairyAdmin admin: list) {
System.out.println(admin);
System.out.println(admin.getCatList());//设置了级联关系,默认自动查询了
}
}
/**
* 多条件查询 方式一
* 需求: 使用ID和用户名进行搜索
*/
@GetMapping("/select2")
public void criteriaQueryTest2() {
//3.实现接口方法specification,添加条件
Specification<FairyAdmin> specification = new Specification<FairyAdmin>(){
/**
* @return Predicate:定义了查询条件
* @param root root:根对象。封装了查询条件的对象
* @param query: query:定义了一个基本的查询.一般不
使用
* @param cb cb:创建一个查询条件
*/
@Override
public javax.persistence.criteria.Predicate toPredicate(Root<FairyAdmin> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>();
list.add(cb.equal(root.get("adminId"),3));
list.add(cb.equal(root.get("adminUsername"), "admin2"));
//此时条件之间是没有任何关系的。
Predicate[] arr = new Predicate[list.size()];
return cb.and(list.toArray(arr));
}
};
//4.执行查询
List<FairyAdmin> list = fairyAdminRepository.findAll(specification);
for (FairyAdmin admin: list) {
System.out.println(admin +"|-------------|");
System.out.println(admin.getCatList() +"|-------------|");//设置了级联关系,默认自动查询了
}
}
/**
* 多条件查询 方式二
* 需求: 使用ID和用户名进行搜索
*/
@GetMapping("/select3")
public void criteriaQueryTest3() {
//3.实现接口方法specification,添加条件
Specification<FairyAdmin> specification = new Specification<FairyAdmin>(){
/**
* @return Predicate:定义了查询条件
* @param root root:根对象。封装了查询条件的对象
* @param query query:定义了一个基本的查询.一般不
使用
* @param cb cb:创建一个查询条件
*/
@Override
public javax.persistence.criteria.Predicate toPredicate(Root<FairyAdmin> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.or(cb.equal(root.get("adminId"),3),cb.equal(root.get("adminUsername"), "admin2"));
}
};
//4.执行查询
List<FairyAdmin> list = fairyAdminRepository.findAll(specification);
for (FairyAdmin admin: list) {
System.out.println(admin +"|-------------|");
System.out.println(admin.getCatList() +"|-------------|");//设置了级联关系,默认自动查询了
}
}
/**
*
* 需求:查询admin用户,并且做分页处理
*/
@GetMapping("/select4")
public void criteriaQueryTest4() {
//条件
Specification<FairyAdmin> spec = new Specification<FairyAdmin>() {
@Override
public Predicate toPredicate(Root<FairyAdmin> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(root.get("adminUsername").as(String.class), "%ad%");
}
};
//分页
Pageable pageable = PageRequest.of(0, 10);
Page<FairyAdmin> page = this.fairyAdminRepository.findAll(spec, pageable);
System.out.println("总条数:"+page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
List<FairyAdmin> list = page.getContent();
for (FairyAdmin admin : list) {
System.out.println(admin +"|-------------|");
System.out.println(admin.getCatList() +"|-------------|");
}
}
/**
*
* 需求:查询数据库中ad姓的用户,并且根据用户 id 做倒序排序
*/
@GetMapping("/select5")
public void criteriaQueryTest5() {
//条件
Specification<FairyAdmin> spec = new Specification<FairyAdmin>() {
@Override
public Predicate toPredicate(Root<FairyAdmin> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(root.get("adminUsername").as(String.class),
"%ad%");
}
};
//排序
Sort sort = Sort.by(Sort.Direction.DESC,"adminId");
List<FairyAdmin> list = this.fairyAdminRepository.findAll(spec, sort);
for (FairyAdmin admin : list) {
System.out.println(admin + "|-------------");
}
}
/**
*
* 需求:查询数据库中ad姓的用户,做分页处理,并且根据用户 id 做倒序排序
*/
@GetMapping("/select6")
public void criteriaQueryTest6() {
//排序等定义
Sort sort = Sort.by(Sort.Direction.DESC,"adminId");
//分页的定义
Pageable pageable = PageRequest.of(0, 10,sort);
//查询条件
Specification<FairyAdmin> spec = new Specification<FairyAdmin>() {
@Override
public Predicate toPredicate(Root<FairyAdmin> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(root.get("adminUsername").as(String.class),
"%ad%");
}
};
Page<FairyAdmin> page = this.fairyAdminRepository.findAll(spec, pageable);
System.out.println("总条数:"+page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
List<FairyAdmin> list = page.getContent();
for (FairyAdmin admin : list) {
System.out.println(admin);
}
}
//方式一:多字段排序查询,无法自定义顺序,输出语句...order by adminId desc, adminUsername desc
Sort sortMulti = Sort.by(Sort.Direction.DESC,"adminId","adminUsername");//可多字段
Sort sort = Sort.by(Sort.Direction.DESC,"adminId");//单字段
//方式二:多字段排序查询,可自定义顺序,x输出语句:...order by adminUsername asc, adminId desc
Sort sort2 = Sort.by(Sort.Direction.DESC,"adminId");//第一个参数,排序类型:ASC/DESC,第二个参数:按照排序的字段,可以设置多个
Sort sort1 = Sort.by(Sort.Direction.ASC,"adminUsername");
final Sort mergeSort = sort1.and(sort);
//方式三:多字段排序查询,先创建order对象,再构造sort
List<Sort.Order> orders = new ArrayList<Sort.Order>();
Sort.Order order1 = new Sort.Order(Sort.Direction.DESC,"adminId");
Sort.Order order2 = new Sort.Order(Sort.Direction.ASC,"adminUsername");
//可以直接单对象创建
Sort orderSort = Sort.by(order2);//...order by adminUsername asc
//可以使用orders列表创建
orders.add(order1);
orders.add(order2);
Sort orderListSort = Sort.by(orders);//...order by adminId desc, adminUsername desc
--------------------------分页-----------------------------------------
//需要注意的是:page从0开始,不是从1开始!
PageRequest pageRequest = PageRequest.of(0,5, orderListSort);//最后一个参数是排序对象
Page<FairyAdmin> content = fairyAdminRepository.findAll(pageRequest);
if (content.hasContent()) {
System.out.println("总记录数:"+content.getTotalElements());
System.out.println("总页数:"+content.getTotalPages());
System.out.println("当前页:"+(content.getPageable().getPageNumber()+1));
System.out.println("当前页面大小:"+content.getPageable().getPageSize());
List<FairyAdmin> list = content.getContent();
list.forEach(System.out::println);
System.out.println(content);
}
//排序和分页
public void sortAndPageSearchTest() {
//排序的几种方式
//方式一:多字段排序查询,无法自定义顺序,输出语句...order by adminId desc, adminUsername desc
//Sort sort = new Sort(Sort.Direction.DESC,"adminId","adminUsername");
//方式二:多字段排序查询,可自定义顺序,x输出语句:...order by adminUsername asc, adminId desc
Sort sort = Sort.by(Sort.Direction.DESC,"adminId");//第一个参数,排序类型:ASC/DESC,第二个参数:按照排序的字段,可以设置多个
Sort sort1 = Sort.by(Sort.Direction.ASC,"adminUsername");
final Sort mergeSort = sort1.and(sort);
//方式三:多字段排序查询,先创建order对象,再构造sort
List<Sort.Order> orders = new ArrayList<Sort.Order>();
Sort.Order order1 = new Sort.Order(Sort.Direction.DESC,"adminId");
Sort.Order order2 = new Sort.Order(Sort.Direction.ASC,"adminUsername");
//可以直接单对象创建
Sort orderSort = Sort.by(order2);//...order by adminUsername asc
//可以使用order列表创建
orders.add(order1);
orders.add(order2);
Sort orderListSort = Sort.by(orders);//...order by adminId desc, adminUsername desc
//需要注意的是:page从0开始,不是从1开始!
PageRequest pageRequest = PageRequest.of(0,5, orderListSort);
Page<FairyAdmin> content = fairyAdminRepository.findAll(pageRequest);
if (content.hasContent()) {
System.out.println("总记录数:"+content.getTotalElements());
System.out.println("总页数:"+content.getTotalPages());
System.out.println("当前页:"+(content.getPageable().getPageNumber()+1));
System.out.println("当前页面大小:"+content.getPageable().getPageSize());
List<FairyAdmin> list = content.getContent();
list.forEach(System.out::println);
System.out.println(content);
}
System.out.println("==========================================");
}