这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战
上一篇我们写的修改是跟保存一样都用的是Save方法,到底有什么不一样呢,我们看看代码
@Transactional
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null.");
if (this.entityInformation.isNew(entity)) {
this.em.persist(entity);
return entity;
} else {
return this.em.merge(entity);
}
}
可以看到先是做了一个判断,isNew(entity),是的话就执行this.em.persist(entity);新增,否的话就执行this.em.merge(entity);去更新。指定了主键主键存在就去修改,指定了主键主键不存在或者不指定主键就区新增 所以我们看控制台就有两条,一条是查询,一条新增或修改。
不指定主键
@Test
public void testUpdate(){
User user = new User();
user.setAge(21);
user.setUserName("李四1109");
user.setAddress("苏高新文体中心");
// user.setId(1);
User save = userRepository.save(user);
}
控制台只有一句Insert
指定主键不存在
@Test
public void testUpdate(){
User user = new User();
user.setAge(21);
user.setUserName("李四1109");
user.setAddress("苏高新文体中心");
user.setId(100);
User save = userRepository.save(user);
}
一条select一条insert
指定主键存在
@Test
public void testUpdate(){
User user = new User();
user.setAge(210);
user.setUserName("李四1109");
user.setAddress("苏高新文体中心");
user.setId(4);
User save = userRepository.save(user);
}
跟我们上边写的一模一样,还有一个根版本判断的我们按下不表
我们在看下保存多个
@Transactional
public <S extends T> List<S> saveAll(Iterable<S> entities) {
Assert.notNull(entities, "Entities must not be null!");
List<S> result = new ArrayList();
Iterator var3 = entities.iterator();
while(var3.hasNext()) {
S entity = var3.next();
result.add(this.save(entity));
}
return result;
}
保存多个我们看到就是它自己写了一个while循环来执行我们的save方法
PagingAndSortingRepository(分页和排序接口)
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
排序
我们排序用的是一个方法,需要一个sort对象来封装我们的排序条件,用Sort.by()返回一个sort对象 都一个参数有两个,表示降序或升序,ASC,DESC;第二个参数表示排序的字段我们先用id排序在根据年龄排,第二个参数可以写多个,现根据第一个排,再根据第二给我排。
public static Sort by(Sort.Direction direction, String... properties) {
Assert.notNull(direction, "Direction must not be null!");
Assert.notNull(properties, "Properties must not be null!");
Assert.isTrue(properties.length > 0, "At least one property must be given!");
return by((List)Arrays.stream(properties).map((it) -> {
return new Sort.Order(direction, it);
}).collect(Collectors.toList()));
}
创建实体类
@Data
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "studentname")
private String studentName;
private Integer age;
private String address;
}
创建接口
public interface StudentRepository extends PagingAndSortingRepository<Student,Integer> {
}
测试类
@Test
public void testSort(){
Iterator<Student> iterator = studentRepository.findAll(Sort.by(Sort.Direction.ASC,"id")).iterator();
while (iterator.hasNext()){
Student next = iterator.next();
System.out.println(next);
}
}
表里数据
控制台输出
根据id排序
根据年龄排序,只需要改一下条件即可
分页
下边是分页和根据年龄排序分页, 分页的对象是一个Pageable对象,这里我们用他的孙子类PageRequest来实现分页,有一个注意点,他分页默认从0页开始,我们下边还有分页的别的方法获取页数,页面,总页数,等等
@Test
public void testPage(){
int page = 1;
int size = 3;
PageRequest pageRequest = PageRequest.of(page, size, Sort.Direction.DESC, "age");
Page<Student> all = studentRepository.findAll(pageRequest);
//Page<Student> all = studentRepository.findAll(PageRequest.of(page, size, Sort.Direction.DESC,"age"));
System.out.println("总页数 :"+ all.getTotalPages());
System.out.println("当前页 :"+ all.getNumber());
System.out.println(",每页显示 :" + all.getSize());
System.out.println("总数量 : "+ all.getTotalElements());
List<Student> content = all.getContent();
for (Student student : content) {
System.out.println(student);
}
}
没有查询条件
有查询条件(上代码注释里的代码)
JpaRepository接口
源码
@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);
<S extends T> List<S> saveAllAndFlush(Iterable<S> entities);
/** @deprecated */
@Deprecated
default void deleteInBatch(Iterable<T> entities) {
this.deleteAllInBatch(entities);
}
void deleteAllInBatch(Iterable<T> entities);
void deleteAllByIdInBatch(Iterable<ID> ids);
void deleteAllInBatch();
/** @deprecated */
@Deprecated
T getOne(ID id);
T getById(ID id);
<S extends T> List<S> findAll(Example<S> example);
<S extends T> List<S> findAll(Example<S> example, Sort sort);
}
我们可以看到JpaRepository接口的查询返回值是list,我们演示一下查询所有
接口集成JpaRepository,参数跟之前crudRepository一样
public interface StudentRepository extends JpaRepository<Student,Integer> {
}
测试类
@Test
public void test1(){
List<Student> all = studentRepository.findAll();
for (Student student : all) {
System.out.println(student);
}
}
输出结果
JpaSpecificationExecutor接口
我们看JpaRepository中没有动态条件查询的方法,这时候我们的接口就要继承JpaSpecificationExecutor, 支持动态分页排序查询。
看下源码有五个方法
第一个条件查询一个
第二个条件查询多个全部展示
第三个条件查询带分页
第四个条件查询带带排序
第五个查个数
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);
}
先改下库里数据
@Test
public void test2(){
//查询条件
StudentVo studentVo = new StudentVo();
studentVo.setStudentName("张三");
studentVo.setAddress("吴中");
studentVo.setAge(30);
//PageRequest定义分页属性
PageRequest pageRequest = PageRequest.of(1, 1, Sort.Direction.DESC, "id");
//调用查询获取结果
Page<Student> all = studentRepository.findAll(new Specification<Student>() {
//在匿名内部类里边拼接条件
@Override
public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Predicate predicate = criteriaBuilder.conjunction();
//判断是否为空
if (studentVo != null) {
//判断条件是否为空
if (!ObjectUtils.isEmpty(studentVo.getStudentName())) {
//拼接查询条件 姓名包含
predicate.getExpressions().add(criteriaBuilder.like(root.get("studentName"), "%" + studentVo.getStudentName() + "%"));
}
//判断条件是否为空
if (!ObjectUtils.isEmpty(studentVo.getAge())) {
//拼接查询条件 大于多少岁
predicate.getExpressions().add(criteriaBuilder.ge(root.get("age"), studentVo.getAge()));
}
//判断条件是否为空
if (!ObjectUtils.isEmpty(studentVo.getAddress())) {
//拼接查询条件 地址包含
predicate.getExpressions().add(criteriaBuilder.like(root.get("address"), "%" + studentVo.getAddress() + "%"));
}
}
return predicate;
}
}, pageRequest);
System.out.println("总页数 :"+ all.getTotalPages());
System.out.println("当前页 :"+ all.getNumber());
System.out.println("每页显示 :" + all.getSize());
System.out.println("总数量 : "+ all.getTotalElements());
List<Student> content = all.getContent();
for (Student student : content) {
System.out.println(student);
}
}
控制台打印结果