一、Spring Data Jpa中的接口:
1.Repository接口:
Repository 接口是 Spring Data JPA 中为我我们提供的所有接口中的顶层接口,Repository 提供了两种查询方式的支持。
(1)基于方法名称命名规则查询;
(2)基于@Query 注解查询;
- 规则:
findBy(关键字)+属性名称(属性名称的首字母大写)+查询条件(首字母大写)。


- 创建接口:
继承Repository接口;方法的名称必须要遵循驼峰式命名规则。findBy(关键字)+属性名称(首字母要大写)+查询条件(首字母大写)。
public interface UsersRepositoryByName extends Repository<Users, Integer> {
List<Users> findByName(String name);
List<Users> findByNameAndAge(String name,Integer age);
List<Users> findByNameLike(String name);
}
- 测试类:
@SpringBootTest
public class ApplicationTest {
@Autowired
private Repositorys repositorys;
@Test
public void findUser() {
List<Users> list = repositorys.findByusername("李四");
for (Users user : list) {
System.out.println(user);
}
}
}
- 基于@Query注解的查询:
通过 JPQL语句查询
JPQL:通过 Hibernate 的 HQL演变过来的。他和 HQL 语法及其相似。
- 创建接口:
public interface UserQuery extends Repository<Users,Integer> {
@Query("from Users where username= :username")
public List<Users> findByName(String username);
@Query("from Users where username like %:username%")
public List<Users> findLikeName(String username);
@Query(value = "select *from users where username=?",nativeQuery = true)
public List<Users> findByNameSQL(String username);
@Query("update Users set username= :username where userid = :userid")
@Modifying
public void updateUser(String username,Integer userid);
}
- 测试:
@SpringBootTest
public class TestQuery {
@Autowired
private UserQuery userQuery;
@Test
public void findByName() {
List<Users> list = userQuery.findByName("李四");
for (Users user:list) {
System.out.println(user);
}
}
@Test
public void findLikeName(){
List<Users> list = userQuery.findLikeName("李");
for (Users user:list) {
System.out.println(user);
}
}
@Test
public void findByNames(){
List<Users> list = userQuery.findByNameSQL("李四");
for (Users user:list) {
System.out.println(user);
}
}
@Test
@Transactional
@Rollback(false)
public void updateUser(){
this.userQuery.updateUser("王五",2);
}
}
2.CrudRepository接口:
- 创建接口:
public interface UserCrudRepository extends CrudRepository<Users,Integer> {
}
- 测试:
@SpringBootTest
public class TestCrud {
@Autowired
private UserCrudRepository userCrudRepository;
@Test
public void saveUser() {
Users users = new Users();
users.setUsername("张三");
users.setUserage(23);
users.setAddress("上海");
userCrudRepository.save(users);
}
@Test
public void updateUser() {
Users users = new Users();
users.setUserid(3);
users.setUsername("张小三");
users.setAddress("郑州");
users.setUserage(18);
}
@Test
public void findOne() {
Optional<Users> optianal = userCrudRepository.findById(3);
Users users = optianal.get();
System.out.println(users);
}
@Test
public void findAll() {
List<Users> list = (List<Users>) userCrudRepository.findAll();
for (Users user : list) {
System.out.println(user);
}
}
@Test
public void deleteUser() {
userCrudRepository.deleteById(3);
}
}
3.JpaRepository接口:
JpaRepository 接口是我们开发时使用的最多的接口。其特点是可以帮助我们将其他接口的方法的返回值做适配处理。可以使得我们在开发时更方便的使用这些方法。
- 创建接口:
public interface UsersRepository extends JpaRepository<Users,Integer> {
}
- 测试:
@SpringBootTest
class SpringdataJpaApplicationTests {
@Autowired
private UsersRepository usersRepository;
//添加
@Test
public void addUser() {
Users users = new Users();
users.setUsername("张三");
users.setUserage(18);
users.setAddress("郑州");
usersRepository.save(users);
}
//查询所有
@Test
public void findAll(){
List<Users> list = usersRepository.findAll();
for (Users user:list) {
System.out.println(user);
}
}
//ID查找
@Test
public void findById(){
Optional<Users> optional = usersRepository.findById(1);
Users users = optional.get();
System.out.println(users);
}
//修改
@Test
public void updateUser(){
Users users = new Users();
users.setUserid(1);
users.setUsername("李四");
users.setUserage(20);
users.setAddress("北京");
usersRepository.save(users);
}
//删除
@Test
public void deleteUser(){
usersRepository.deleteById(2);
}
}
4.PagingAndSortingRepository接口
- 创建接口:
public interface UserPageAndSort extends PagingAndSortingRepository<Users,Integer> {
}
- 测试:
/**
* 排序分页测试
*/
@SpringBootTest
public class TestPageAndSort {
@Autowired
private UserPageAndSort userPageAndSort;
@Test
public void TestSort(){
//创建Order对象
Sort.Order order = Sort.Order.desc("userid");
Sort sort = Sort.by(order);
Iterable<Users> iterable = userPageAndSort.findAll(sort);
for (Users user:iterable){
System.out.println(user);
}
}
@Test
public void TestPage(){
//Pageable:封装了分页的参数,当前页,每页显示的条数。当前页是从0开始。
//PageRequest(page,size) page:当前页。size:每页显示的条数
// Pageable pageable = new PageRequest(1,2); //低版本
PageRequest pageRequest = PageRequest.of(0, 2);
Page<Users> page = userPageAndSort.findAll(pageRequest);
System.out.println("总条数:"+page.getTotalElements()+";总页数:"+page.getTotalPages());
List<Users> list = page.getContent();
for (Users user:list){
System.out.println(user);
}
}
@Test
public void PageAndSort(){
Sort.Order order= Sort.Order.desc("userid");
Sort sort= Sort.by(order);
PageRequest pageRequest = PageRequest.of(0,2,sort);
Page<Users> page = userPageAndSort.findAll(pageRequest);
System.out.println("总条数:"+page.getTotalElements()+";总页数:"+page.getTotalPages());
List<Users> list = page.getContent();
for (Users user:list) {
System.out.println(user);
}
}
}
5.JpaSpecificationException接口:
JpaSpecificationExecutor接口主要提供了多条件查询的支持,并且可以在查询中添加分页与排序。
注意:JpaSpecificationExecutor接口
与以上接口没有关系,完全独立。不能单独使用,需要配合着 jpa 中的其他接口一起使用。
- 创建接口:
public interface UserJpaSpecificationExecutor extends JpaSpecificationExecutor<Users>, JpaRepository<Users,Integer> {
}
- 测试:
@SpringBootTest
public class TestJpaSpecificationExcutor {
@Autowired
private UserJpaSpecificationExecutor userJpaSpecificationExecutor;
//单条件测试
@Test
public void TestJpaRepository(){
//封装查询条件
Specification<Users> specification = new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Predicate predicate = criteriaBuilder.equal(root.get("username"), "张三");
return predicate;
}
};
List<Users> list = userJpaSpecificationExecutor.findAll(specification);
for (Users user:list) {
System.out.println(user);
}
}
//多条件查询
@Test
public void TestJapSpecificationExecutor(){
Specification<Users> specification = new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
ArrayList<Predicate> list = new ArrayList<>();
list.add(criteriaBuilder.equal(root.get("username"),"张三"));
list.add(criteriaBuilder.equal(root.get("userage"),23));
Predicate[] predicates = new Predicate[1];
return criteriaBuilder.and(list.toArray(predicates));
}
};
List<Users> list = userJpaSpecificationExecutor.findAll(specification);
for (Users user:list){
System.out.println(user);
}
}
@Test
public void testFindAll(){
Specification<Users> specification = new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.and(criteriaBuilder.like(root.get("username"),"%张%"),criteriaBuilder.ge(root.get("userage"),23));
}
};
Sort.Order o = Sort.Order.desc("userage");
Sort sort = Sort.by(o);
PageRequest pageRequest = PageRequest.of(0, 2, sort);
Page<Users> page = userJpaSpecificationExecutor.findAll(specification,pageRequest);
System.out.println("总条数:"+page.getTotalElements()+";总页数"+page.getTotalPages());
for (Users user:page){
System.out.println(user);
}
}
}
二、关联查询
JPA定义了一个OneToMany关系,它与ManyToMany关系类似,但反向关系(如果已定义)是ManyToOne关系。 OneToMany与JPA中ManyToMany关系的主要区别在于,ManyToMany总是使用中间关系连接表来存储关系,OneToMany可以使用连接表或者目标对象的表引用中的外键源对象表的主键。
1.一对一关联查询:
需求:用户与身份的一对一的关联关系
用户:一方
身份证:一方
- 创建用户:
@Entity
@Table
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int perid;
@Column
private String pername;
public int getPerid() {
return perid;
}
public void setPerid(int perid) {
this.perid = perid;
}
public String getPername() {
return pername;
}
public void setPername(String pername) {
this.pername = pername;
}
}
- 创建IdCard:
@Entity
@Table
public class IdCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int cardid;
@Column
private String cardnum;
//cascade代表级联操作
@OneToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "perid")
private Person person;//一对一关系
public int getCardid() {
return cardid;
}
public void setCardid(int cardid) {
this.cardid = cardid;
}
public String getCardnum() {
return cardnum;
}
public void setCardnum(String cardnum) {
this.cardnum = cardnum;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
- 创建接口:
public interface PersonJpaRepository extends JpaRepository<IdCard,Integer> {
}
- 测试:
@SpringBootTest
public class TestPerson {
@Autowired
private PersonJpaRepository personJpaRepository;
@Test
public void testAdd() {
Person person = new Person();
person.setPername("张三");
IdCard idCard = new IdCard();
idCard.setCardnum("412722199910101234");
idCard.setPerson(person);
personJpaRepository.save(idCard);
}
@Test
public void testFindAll(){
List<IdCard> list = personJpaRepository.findAll();
for (IdCard idcard:list) {
System.out.println(idcard);
}
}
}
2.一对多关联查询:
需求:从员工和部门的一对多的关联关系
部门:一方
员工:多方

- 创建员工实体:
@Entity
@Table
public class Emp {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int empid;
@Column
private String empname;
@ManyToOne(cascade = CascadeType.PERSIST)//多对一关系
@JoinColumn(name = "deptid")
private Dept dept;
public int getEmpid() {
return empid;
}
public void setEmpid(int empid) {
this.empid = empid;
}
public String getEmpname() {
return empname;
}
public void setEmpname(String empname) {
this.empname = empname;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
}
- 创建部门实体:
@Entity
@Table
public class Dept {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int deptid;
@Column
private String deptname;
@OneToMany(mappedBy = "dept")//mappedBy用于指定关系维护
private Set<Emp> emp=new HashSet<>();
public int getDeptid() {
return deptid;
}
public void setDeptid(int deptid) {
this.deptid = deptid;
}
public String getDeptname() {
return deptname;
}
public void setDeptname(String deptname) {
this.deptname = deptname;
}
public Set<Emp> getEmp() {
return emp;
}
public void setEmp(Set<Emp> emp) {
this.emp = emp;
}
}
- 创建接口:
public interface EmpJpaRepository extends JpaRepository<Emp,Integer> {
}
- 测试:
@SpringBootTest
public class TestEmp {
@Autowired
private EmpJpaRepository empJpaRepository;
@Test
public void TestAdd(){
Dept dept = new Dept();
dept.setDeptname("人事部");
Emp emp = new Emp();
emp.setEmpname("Admin");
emp.setDept(dept);
empJpaRepository.save(emp);
}
@Test
public void testFindAll(){
List<Emp> list = empJpaRepository.findAll();
for (Emp emp:list){
System.out.println(emp);
}
}
}

3.多对多关联查询:
需求:一个学生可以拥有多个课程,一个课程可以分配多个学生。
多对多的关联关系
学生:多方
课程:多方
-
创建学生实体:
多对多数据库模型
@Entity
@Table
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int stuid;
@Column
private String stuname;
@ManyToMany(cascade = CascadeType.PERSIST)
@JoinTable(name = "stu_cou",joinColumns = @JoinColumn(name = "stuid"),
inverseJoinColumns = @JoinColumn(name = "couid"))
private Set<Course> course = new HashSet<>();
public int getStuid() {
return stuid;
}
public void setStuid(int stuid) {
this.stuid = stuid;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public Set<Course> getCourse() {
return course;
}
public void setCourse(Set<Course> course) {
this.course = course;
}
}
- 创建课程实体:
@Entity
@Table
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int couid;
@Column
private String couname;
//维护关系,mappedBy=“对方和当前对象关联的对象名称”
@ManyToMany(mappedBy = "course")
private Set<Student> students = new HashSet<>();
public int getCouid() {
return couid;
}
public void setCouid(int couid) {
this.couid = couid;
}
public String getCouname() {
return couname;
}
public void setCouname(String couname) {
this.couname = couname;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
- 创建接口:
public interface StudentJpaRepository extends JpaRepository<Student,Integer> {
}
- 测试:
@SpringBootTest
public class TestStudent {
@Autowired
StudentJpaRepository studentJpaRepository;
@Test
public void testAdd(){
Student student = new Student();
student.setStuname("张三");
Course course = new Course();
course.setCouname("Java");
Course course1 = new Course();
course1.setCouname("C++");
student.getCourse().add(course);
student.getCourse().add(course1);
studentJpaRepository.save(student);
}
}
4.使用的注解:
(1)@JoinTable:配置中间表信息;
joinColumns:建立当前表在中间表中的外键字段;
(2)一对一:@OneToOne;
一对多:@OneToMany;
多对一:@ManyToOne;
多对多:@ManyToMany;
(3)@Table:声明此对象映射到数据库的数据表,通过它可以为实体指定表(talbe);
(4)@GeneratedValue(strategy=GenerationType.IDENTITY):注解存在的意义主要就是为一个实体生成一个唯一标识的主键(JPA要求每一个实体Entity,必须有且只有一个主键);
- mappedBy 属性:
mappedBy是OneToOne、OneToMany和ManyToMany这三种关联关系的属性。用来标注拥有这种关系的字段。 除非关系是单向的,否则是必需的。那么什么叫拥有关联关系呢,假设是双向一对一的话,那么拥有关系的这一方有建立、解除和更新与另一方关系的能力。而另一方没有,只能被动管理。由于JoinTable和JoinColumn一般定义在拥有关系的这一端,而mappedBy一定是定义在关系的被拥有方(the owned side),也就是跟定义JoinTable和JoinColumn互斥的一方,它的值指向拥有方中关于被拥有方的字段,可能是一个对象(OneToMany),也可能是一个对象集合(ManyToMany)。
- 级联关系类型:
(1)CascadeType.REFRESH:级联刷新,当多个用户同时作操作一个实体,为了用户取到的数据是实时的,在用实体中的数据之前就可以调用一下refresh()方法。
(2)CascadeType.REMOVE:级联删除,当调用remove()方法删除Order实体时会先级联删除OrderItem的相关数据。
(3)CascadeType.MERGE:级联更新,当调用了Merge()方法,如果Order中的数据改变了会相应的更新OrderItem中的数据。
(4)CascadeType.ALL:包含以上所有级联属性。
(5)CascadeType.PERSIST:级联保存,当调用了Persist() 方法,会级联保存相应的数据。
网友评论