写在前面:从2018年底开始学习SpringBoot,也用SpringBoot写过一些项目。现在对学习Springboot的一些知识总结记录一下。如果你也在学习SpringBoot,可以关注我,一起学习,一起进步。相关文章:初识Spring-Data-Jpa
相关文章:
【Springboot系列】Springboot入门到项目实战
目录
上一篇讲了Spring-Data-Jpa入门,这一篇来看一下Spring-Data-Jpa条件查询(基于上一篇Spring-Data-Jpa入门的项目中写的,配置文件没有任何改动,详情可以参考Spring-Data-Jpa入门)。
Spring-Data-Jpa条件查询
按照SpringData的规则,可以通过定义在Repository接口下的方法名称来执行查询等操作,查询的方法名称必须以find、get、read、开头,同时,涉及条件查询时,SpringDataJpa支持将条件属性定义在数据访问层接口下的方法名称中,条件属性通过条件关键字链接。需要注意:条件属性的首字母必须大写。
编写代码
1、创建持久化类
在entity包中创建一个持久化类Student.java,代码如下
//用于标记持久化类,SpringBoot项目加载后会自动根据持久化类建表
@Entity
//设置表名为tb_student
@Table(name="tb_student")
public class Student {
/**
* 使用@id指定主键。使用代码@GeneratedValue(strategy = GenerationType.IDENTITY)
* 指定主键的生存策略,mysql默认为自动增长
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id; //主键
private String name; //姓名
private String address; //地址
private Integer age; //年龄
private char sex; //性别
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public Student() {
}
public Student(String name, String address, Integer age, char sex) {
this.name = name;
this.address = address;
this.age = age;
this.sex = sex;
}
}
2、定义数据访问层接口
在定义数据访问层接口前,先来了解一下JpaRepository接口。
JpaRepository继承值PagingAndSortingRepository接口,因此将获得更多的操作功能,JpaRepository是基于JPA的Repository接口,他极大的减少了JPA作为数据访问的代码,JpaRepository是实现SpringDataJpa技术访问数据库的关键接口。JpaRepository接口的源码如下
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);
}
该接口提供的常用方法如下
- List<T> findAll(); 查询所有的实体对象数据,返回一个List集合。
- List<T> findAll(Sort var1); 按照指定的排序对象规则查询实体对象数据,返回的是一个List集合
- List<T> findAllById(Iterable<ID> var1); 根据所提供的实体对象id,将对应的实体全部查询出来,返回的是一个List集合
- <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); 根据id查询出对应的实体对象。
- <S extends T> List<S> findAll(Example<S> var1); 根据提供的example实例查询实体对象数据。
- <S extends T> List<S> findAll(Example<S> var1, Sort var2); 根据提供的example实例查询实体对象数据,同时支持排序查询。
之后在repository包下新建一个接口,命名为StudentRepository,该接口继承JpaRepository接口,以持久化对象Student作为JpaRepository的第一个类型参数,表示当前所操作的持久化对象类型,Integer作为JpaRepository的第二稿类型参数,用于指定ID类型。
StudentRepository接口中定义了三个方法,分别是findByName,通过学生性别来查询学生对象;,findByNameAndAddress,通过名字和地址查询学生信息;findByNameLike,通过学生姓名模糊查询学生信息。具体代码如下
import com.mcy.springdatajpa.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface StudentRepository extends JpaRepository<Student, Integer> {
/**
* 通过学生性别来查询学生对象
* 此方法相当于JPQL语句代码:select s from student s where s.name=?1
* @param name
* @return
*/
Student findByName(String name);
/**
* 通过名字和地址查询学生信息
* 此方法相当于JPQL语句代码:select s from student s where s.name = ?1 and s.address=?2
* @param name
* @param address
* @return 包含Student对象的List集合
*/
List<Student> findByNameAndAddress(String name, String address);
/**
* 通过学生姓名模糊查询学生信息
* 此方法相当于JPQL语句代码:select s from student s where s.name list ?1
* @param name
* @return 包含Student对象的List集合
*/
List<Student> findByNameLike(String name);
}
从上述代码可以看出,findByName(String name)方法等同于JPQL语句:select s from student s where s.name=?1,因为by是条件关键字,而name是条件属性,条件关键字和条件属性的首字母必须大写,所以上述方法名的定义即findByName。从这里可以看出在SpringDataJpa中可以直接通过在数据访问层定义方法名称即可以进行数据的访问操作了。
findByNameAndAddress(String name, String address)方法相当于JPQL语句:select s from student s where s.name = ?1 and s.address=?2。其中by和and是条件关键字,name和address是条件属性。
findByNameLike(String name)方法,相当于JPQL语句:select s from student s where s.name list ?1,其中by和like是条件关键字,name是条件属性。
除此之外,还有很多形式的命名查询方式,可以参考Spring-Data-Jpa命名规范
3、定义业务层类
在service包下新建一个StudentService类,代码如下(几个条件查询方法)。
import javax.annotation.Resource;
import java.util.List;
@Service
public class StudentService {
//注入数据访问层接口对象
@Resource
private StudentRepository studentRepository;
//事务管理
@Transactional
public void saveAll(List<Student> students){
studentRepository.saveAll(students);
}
public Student getStuByName(String name){
return studentRepository.findByName(name);
}
public List<Student> getStusByNameAndAddr(String name, String address){
return studentRepository.findByNameAndAddress(name, address);
}
public List<Student> getStusByNameLike(String name){
return studentRepository.findByNameLike("%"+name+"%");
}
}
在业务层中需要注入数据访问层对象,在上述代码中是通过@Resource注解将StudentRepository接口对应的实现类对象注入进行的。
4、定义控制器类
在controller包下新建一个StudentController类,代码如下。
import com.mcy.springdatajpa.entity.Student;
import com.mcy.springdatajpa.service.StudentService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/student")
public class StudentController {
//注入StudentService
@Resource
private StudentService studentService;
@RequestMapping("/save")
public String save(){
Student student = new Student();
student.setAddress("湖北");
student.setName("张三");
student.setAge(18);
student.setSex('男');
Student student2 = new Student();
student2.setAddress("湖北");
student2.setName("李四");
student2.setAge(19);
student2.setSex('男');
Student student3 = new Student();
student3.setAddress("湖北");
student3.setName("王五");
student3.setAge(20);
student3.setSex('男');
List<Student> students = new ArrayList<>();
students.add(student);
students.add(student2);
students.add(student3);
//保存
studentService.saveAll(students);
return "保存学生对象成功";
}
@RequestMapping("/name")
public Student getByName(String name){
return studentService.getStuByName(name);
}
@RequestMapping("/nameAndAddress")
public List<Student> getNameAndAddress(String name, String address){
return studentService.getStusByNameAndAddr(name, address);
}
@RequestMapping("/nameLike")
public List<Student> getByNameLike(String name){
return studentService.getStusByNameLike(name);
}
}
测试应用
1、测试应用
启动MySQL数据库,在数据库中创建名为jpa的数据库。springboot项目启动后,JPA会在数据库中自动创建持久化类对应的tb_student表。
测试添加学生信息,在浏览器中输入http://localhost:8080/student/save地址,请求会提交到StudentController类的save方法进行处理,执行完成返回“保存学生对象成功”。
数据库中添加了StudentController类的save方法中对应的三条数据。
测试根据姓名查询学生对象,在浏览器中输入http://localhost:8080/student/name?name=张三地址,请求会提交到StudentController类的getByName方法进行处理,执行完成返回查询出的学生对象,如下图
测试根据姓名和地址查询地址查询学生对象,在浏览器中输入http://localhost:8080/student/name?name=张三&address=湖北地址,请求会提交到StudentController类的getNameAndAddress方法进行处理,执行完成返回查询出的学生对象,如图
测试根据姓名模糊查询学生对象,在浏览器中输入http://localhost:8080/student/nameLike?name=李地址,请求会提交到StudentController类的getByNameLike方法进行处理,执行完成返回查询出的学生对象,如图