SpringData JPA学习笔记
SpringData JPA
环境准备
情景需要:创建spring boot项目,整合spring data jpa项目使用
环境要求:
JDK8+
Maven3+
Intellij IDEA
Spring Boot2+
MySQL8+
Spring Data JPA
pom.xml
<!--spring data jpa依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
application,properties
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/jpa?useUnicode=true&characterEncoding=UTF8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
#创建数据库的方式类型
spring.jpa.hibernate.ddl-auto=update
#显示sql语句
spring.jpa.show-sql=true
Repository接口
Repository 位于 Spring Data Common 的 lib 里面,是 Spring Data 里面做数据库操作的最底层的抽象接口,最*的父类,源码
里面其实什么方法都没有,仅仅起到一个标识作用。管理域类以及域类的 ID 类型作为类型参数,此接口主要作为标记接口来捕获
要使用的类型,并帮助用户发现扩展此接口的接口。Spring 底层做动态代理的时候发现只要是它的子类或者实现类,都代表储存
库操作。
package org.springframework.data.repository;
import org.springframework.stereotype.Indexed;
@Indexed
public interface Repository<T, ID> {
}
CrudRepository接口
package org.springframework.data.repository;
import java.util.Optional;
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
//保存或修改
<S extends T> S save(S var1);//(1)
//批量保存
<S extends T> Iterable<S> saveAll(Iterable<S> var1);//(2)
//根据主键查询实体
Optional<T> findById(ID var1);//(3)
//根据主键判断实体是否存在
boolean existsById(ID var1);//(4)
//查询实体的所有列表
Iterable<T> findAll//(5)
//根据主键列表查询实体列表
Iterable<T> findAllById(Iterable<ID> var1);//(6)
//查询总数
long count();//(7)
//根据主键删除
void deleteById(ID var1);//(8)
//根据实体对象删除
void delete(T var1);//(9)
//根据实体对象批量删除
void deleteAll(Iterable<? extends T> var1);//(10)
//删除所有数据
void deleteAll();//(11)
PagingAndSortingRepository接口
它继承了CrudRepository接口,所以它也具备简单的增删改查
package org.springframework.data.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
//查询列表,支持排序
Iterable<T> findAll(Sort var1);
//分页查询
Page<T> findAll(Pageable var1);
}
使用
定义UserRepository接口
package com.kazu.springdatajpa01.dao;
import com.kazu.springdatajpa01.entity.User;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface UserPagingAndSortingRepository extends PagingAndSortingRepository<User,Integer> {
}
测试类
public class UserPagingAndSortingRepositoryTest {
@Resource
private UserRepository userRepository;
/**
* 排序查询
*/
@Test
public void testFindAllBySort(){
//创建排序对象(参数1:升序或降序,参数2:排序属性名)
Sort sort = new Sort(Sort.Direction.DESC,"id");
//调用查询方法
Iterable<User> userIterable = userRepository.findAll(sort);
//获取查询迭代器
Iterator<User> userIterator = userIterable.iterator();
//循环遍历
while(userIterator.hasNext()){
//获取每一个用户对象
User user = userIterator.next();
System.out.println(user);
}
}
/**
* 排序分页查询
*/
@Test
//分页查询
public void testPage() {
int pageNo = 1;
int pageSize = 3;
//设置分页信息
PageRequest pageRequest = PageRequest.of(pageNo-1, pageSize); //页码从0开始
//调用分页查询,获得分页对象
Page<Student> page = studentRepository.findAll(pageRequest);
System.out.println("当前页码:"+(page.getNumber()+1));
System.out.println("每页显示条数:"+page.getSize());
System.out.println("总记录数:"+page.getTotalElements());
System.out.println("总页码:"+page.getTotalPages());
List<Student> list = page.getContent();
list.forEach(System.out::println);
}
}
JpaRepository接口(常用)
它继承了PagingAndSortingRepository,所以它具备简单的增删改查和分页排序
package org.springframework.data.jpa.repository;
import java.util.List;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>,
QueryByExampleExecutor<T> {
List<T> findAll();
List<T> findAll(Sort var1);
List<T> findAllById(Iterable<ID> var1);
<S extends T> List<S> saveAll(Iterable<S> var1);
void flush();
<S extends T> S saveAndFlush(S var1);
void deleteInBatch(Iterable<T> var1);
void deleteAllInBatch();
T getOne(ID var1);
<S extends T> List<S> findAll(Example<S> var1);
<S extends T> List<S> findAll(Example<S> var1, Sort var2);
}
重点关注查询方法,通过源码和CrudRepository接口相比较,JpaRepository接口将默认实现的查询结果换成了List。
JpaSpecificationExecutor接口
package org.springframework.data.jpa.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;
public interface JpaSpecificationExecutor<T> {
Optional<T> findOne(@Nullable Specification<T> var1);
List<T> findAll(@Nullable Specification<T> var1);
//分页查询(支持动态查询+分页查询+排序)
Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);
List<T> findAll(@Nullable Specification<T> var1, Sort var2);
long count(@Nullable Specification<T> var1);
}
重点关注Page findAll(@Nullable Specification var1, Pageable var2)此方法
使用
定义接口
package com.kazu.springdatajpa01.dao;
import com.kazu.springdatajpa01.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* 分页查询(支持动态查询+分页查询+排序)
*/
public interface UserRepository extends JpaRepository<User,Integer>,JpaSpecificationExecutor<User> {
}
测试类
@Test
//动态条件查询
public void test01() {
//创建查询条件对象
Person person = new Person();
person.setAddress("广州");
person.setAge(29);
//调用动态查询方法
List<Person> list = personRepository.findAll(new Specification<Person>() {
@Override
/**
* -Root:对应实体的成员变量
* -CriteriaBuilder:帮助我们制作查询信息
*/
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> criteriaQuery,CriteriaBuilder cb) {
//获取条件参数对象
Predicate predicate = cb.conjunction();
//person对象不为空
if(person!=null){
//用户名
if(!ObjectUtils.isEmpty(person.getName())){
//模糊查询
predicate.getExpressions().add(cb.like(root.get("name"),"%"+person.getName()+"%"));
}
//年龄
if(!ObjectUtils.isEmpty(person.getAge())){
//大于等于
predicate.getExpressions().add(cb.greaterThan(root.get("age"), person.getAge()));
//年龄等于
//predicate.getExpressions().add(cb.equal(root.get("age"), person.getAge()));
}
//地址
if(!ObjectUtils.isEmpty(person.getAddress())){
//模糊查询
predicate.getExpressions().add(cb.like(root.get("address"),"%"+person.getAddress()+"%"));
}
}
return predicate;
}
});
list.forEach(System.out::println);
}
@Test
//动态条件分页查询
public void test02() {
//创建查询条件对象
Person person = new Person();
person.setAddress("广州");
//创建分页对象
//从页码0开始,每页3条
PageRequest pageRequest = PageRequest.of(0, 3, Sort.Direction.ASC, "id");
//调用动态查询方法
Page<Person> page = personRepository.findAll(new Specification<Person>() {
@Override
/**
* -Root:对应实体的成员变量
* -CriteriaBuilder:帮助我们制作查询信息
*/
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> criteriaQuery,CriteriaBuilder cb) {
//获取条件参数对象
Predicate predicate = cb.conjunction();
//person对象不为空
if(person!=null){
//用户名
if(!ObjectUtils.isEmpty(person.getName())){
//模糊查询
predicate.getExpressions().add(cb.like(root.get("name"),"%"+person.getName()+"%"));
}
//年龄
if(!ObjectUtils.isEmpty(person.getAge())){
//大于等于
predicate.getExpressions().add(cb.ge(root.get("age"),person.getAge()));
}
//地址
if(!ObjectUtils.isEmpty(person.getAddress())){
//模糊查询
predicate.getExpressions().add(cb.like(root.get("address"),"%"+person.getAddress()+"%"));
}
}
return predicate;
}
},pageRequest);
//输出分页信息
System.out.println("当前页码:"+(page.getNumber()+1));
System.out.println("每页显示条数:"+page.getSize());
System.out.println("总记录数:"+page.getTotalElements());
System.out.println("总页码:"+page.getTotalPages());
List<Person> list = page.getContent();
list.forEach(System.out::println);
}
方法命名查询
概述
顾名思义,方法命名规则查询就是根据方法的名字,就能创建查询。只需要按照Spring Data JPA提供的方法命名规则定义方法的
名称,就可以完成查询工作。Spring Data JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询
按照Spring Data JPA 定义的规则,查询方法以 findBy 开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。
关键字
Keyword | sample | JPQL |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | 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 | findByAgeGreaterThanEqua | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
上一篇: Jpa的学习笔记