欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringData JPA学习笔记

程序员文章站 2022-04-22 08:01:17
...

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