当前位置:   article > 正文

Spring Data JPA的一对一多表查询_jpa一对一关联查询

jpa一对一关联查询

一、简单聊聊

        我在写自己的课程设计的时候,用的持久层API就是JPA。整个项目给我带来的感受就是:低SQL语句开发,甚至是零SQL语句开发,使得我在开发过程中,不再关注SQL语句的书写问题与逻辑问题。这使得我在开发过程中,更加专注于自己的业务逻辑,而不在拘泥于SQL表和Java实体之间的映射。尤其在多表查询这一块,JPA以其超简洁的语法规则,给我们实现了表一对一乃至一对多的关系。那么今天想给大家分享的是,一对一的多表查询。

二、简单认识JPA

以下引用了网上对JPA的介绍:

        JPA是Java Persistence API的简称,中文名为Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

        Spring Data Common是Spring Data所有模块的公用部分,该项目提供跨Spring数据项目的共享基础设施。它包含了技术中立的库接口以及一个坚持java类的元数据模型。

  Spring Data不仅对传统的数据库访问技术JDBC、Hibernate、JDO、TopLick、JPA、Mybitas做了很好的支持、扩展、抽象、提供方便的API,还对NoSQL等非关系数据做了很好的支持,包括MongoDB、Redis、Apache Solr等。

三、Spring Data JPA的环境搭建

        首先我们使用的环境是Spring Boot环境。相信读者都应该会新建一个springboot的项目了,因此以下进行简单的环境搭建截图:

        

 这里需要注意一下,我用的版本是2.6.0版本。

 四、使用MYSQL数据库创建student和teacher表

         创建表的SQL语句如下所示:

         值得注意的是,这里的students表的外键是teacher_id,它关联的是teacher表的teacher_id。

  1. SET FOREIGN_KEY_CHECKS=0;
  2. -- ----------------------------
  3. -- Table structure for student
  4. -- ----------------------------
  5. DROP TABLE IF EXISTS `student`;
  6. CREATE TABLE `student` (
  7. `id` int(10) NOT NULL AUTO_INCREMENT,
  8. `stu_no` varchar(20) NOT NULL,
  9. `stu_name` varchar(50) DEFAULT NULL,
  10. `teacher_id` int(10) NOT NULL,
  11. PRIMARY KEY (`id`),
  12. KEY `teacher_id` (`teacher_id`),
  13. CONSTRAINT `student_ibfk_1` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`teacher_id`)
  14. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
  15. -- ----------------------------
  16. -- Records of student
  17. -- ----------------------------
  18. INSERT INTO `student` VALUES ('1', 'stu01', '柏拉图', '1');
  19. INSERT INTO `student` VALUES ('2', 'stu01', '亚里士多德', '1');
  20. -- ----------------------------
  21. -- Table structure for teacher
  22. -- ----------------------------
  23. DROP TABLE IF EXISTS `teacher`;
  24. CREATE TABLE `teacher` (
  25. `teacher_id` int(10) NOT NULL AUTO_INCREMENT,
  26. `teacher_name` varchar(50) DEFAULT NULL,
  27. PRIMARY KEY (`teacher_id`)
  28. ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  29. -- ----------------------------
  30. -- Records of teacher
  31. -- ----------------------------
  32. INSERT INTO `teacher` VALUES ('1', '苏格拉底');

五、接下来我们来创建两个实体类(teacher和student)

  1. package cn.com.demo.springdatajpa.pojo;
  2. import jdk.nashorn.internal.objects.annotations.Getter;
  3. import jdk.nashorn.internal.objects.annotations.Setter;
  4. import javax.persistence.*;
  5. // 该注解目的是为了标记他为一个实体类
  6. @Entity
  7. // 映射数据库中的student表
  8. @Table(name = "student")
  9. public class student {
  10. //标记为主键
  11. @Id
  12. // 申明主键生成策略 自动增长
  13. @GeneratedValue(strategy = GenerationType.IDENTITY)
  14. private Integer id;
  15. // 将此属性与数据库表中的stu_no进行对应
  16. @Column(name = "stu_no")
  17. private String stuNo;
  18. @Column(name = "stu_name")
  19. private String stuName;
  20. @Column(name = "teacher_id")
  21. private String teacherId;
  22. public Integer getId() {
  23. return id;
  24. }
  25. public String getStuNo() {
  26. return stuNo;
  27. }
  28. public String getStuName() {
  29. return stuName;
  30. }
  31. public String getTeacherId() {
  32. return teacherId;
  33. }
  34. public void setId(Integer id) {
  35. this.id = id;
  36. }
  37. public void setStuNo(String stuNo) {
  38. this.stuNo = stuNo;
  39. }
  40. public void setStuName(String stuName) {
  41. this.stuName = stuName;
  42. }
  43. public void setTeacherId(String teacherId) {
  44. this.teacherId = teacherId;
  45. }
  46. @Override
  47. public String toString() {
  48. return "student{" +
  49. "id=" + id +
  50. ", stuNo='" + stuNo + '\'' +
  51. ", stuName='" + stuName + '\'' +
  52. ", teacherId='" + teacherId + '\'' +
  53. '}';
  54. }
  55. }
  1. package cn.com.demo.springdatajpa.pojo;
  2. import javax.persistence.*;
  3. @Entity
  4. @Table(name = "teacher")
  5. public class teacher {
  6. @Id
  7. @GeneratedValue(strategy = GenerationType.IDENTITY)
  8. private Integer teacherId;
  9. @Column(name = "teacher_name")
  10. private String teacherName;
  11. public Integer getTeacherId() {
  12. return teacherId;
  13. }
  14. public void setTeacherId(Integer teacherId) {
  15. this.teacherId = teacherId;
  16. }
  17. public String getTeacherName() {
  18. return teacherName;
  19. }
  20. public void setTeacherName(String teacherName) {
  21. this.teacherName = teacherName;
  22. }
  23. @Override
  24. public String toString() {
  25. return "teacher{" +
  26. "teacherId=" + teacherId +
  27. ", teacherName='" + teacherName + '\'' +
  28. '}';
  29. }
  30. }

 六、创建两个持久层接口teacherDao、studentDao

  1. package cn.com.demo.springdatajpa.dao;
  2. import cn.com.demo.springdatajpa.pojo.teacher;
  3. import org.springframework.data.jpa.repository.JpaRepository;
  4. import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
  5. public interface teacherDao extends JpaRepository<teacher,Integer>, JpaSpecificationExecutor<teacher> {
  6. }
  1. package cn.com.demo.springdatajpa.dao;
  2. import cn.com.demo.springdatajpa.pojo.student;
  3. import org.springframework.data.jpa.repository.JpaRepository;
  4. import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
  5. public interface studentDao extends JpaRepository<student,Integer>, JpaSpecificationExecutor<student> {
  6. }

七、先做一个简单的测试

        1、在application.properties里面进行数据库的配置和jpa的配置

  1. # 配置数据的连接信息
  2. spring.datasource.driver-class-name=com.mysql.jdbc.Driver
  3. spring.datasource.url=jdbc:mysql://localhost:3306/school&useUnicode=true&characterEncoding=utf8
  4. spring.datasource.username=root
  5. spring.datasource.password=root
  6. spring.jpa.show-sql=true
  7. spring.jpa.hibernate.ddl-auto=update
  8. spring.jpa.database=MySQL
  9. spring.jpa.generate-ddl=true
  10. spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy

              2、在test目录下的SpringDataJPATest中进行测试

  1. package cn.com.demo.springdatajpa;
  2. import cn.com.demo.springdatajpa.dao.studentDao;
  3. import cn.com.demo.springdatajpa.dao.teacherDao;
  4. import cn.com.demo.springdatajpa.pojo.student;
  5. import cn.com.demo.springdatajpa.pojo.teacher;
  6. import org.junit.jupiter.api.Test;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.boot.test.context.SpringBootTest;
  9. import java.util.List;
  10. @SpringBootTest
  11. class SpringDataJpaApplicationTests {
  12. @Autowired
  13. private teacherDao teacherDao;
  14. @Autowired
  15. private studentDao studentDao;
  16. @Test
  17. void contextLoads() {
  18. List<teacher> teachers= teacherDao.findAll();
  19. List<student> students= studentDao.findAll();
  20. System.out.println("学生:"+students);
  21. System.out.println("教师:"+teachers);
  22. }
  23. }

 我们来看看测试结果:

 八、实现表的一一关联

        在上面的结果中,我们很明显的看到,两张表的数据是没有任何关联的。那么要实现一对一的表关联,我们就要确认在哪一方添加一个关联对象。很明显我们需要在有外键的一方,添加外键,添加的语句就是

  1. @JoinColumn(name = "teacher_id",insertable = false,updatable = false)
  2. @OneToOne(targetEntity=teacher.class,cascade=CascadeType.DETACH)
  3. private teacher teacher;

其中@JoinColumn表示添加一个查询字段,整个字段要以teacher_id作为关联查询条件,并且insertable和updateable表示不更新此字段。@OneToOne注解则表示:如果更具teacher_id查询到一个关联的结果集,就把他封装成teacher这个实体,并且他的级联级别是DETACH(级联实体分离操作),也就是说:分离所有相关联的实体,该实体已在数据库中,对象将处于分离状态,对该对象的操作不会同步到数据库。

除此之外,级联级别还包括:

ALL(级联所有实体状态转换)

PERSIST(级联实体持久化操作)

MERGE(级联实体合并操作)

REMOVE(级联实体删除操作)

REFRESH(级联实体刷新操作)

因此,我们就把实体类student变成这个样子

  1. package cn.com.demo.springdatajpa.pojo;
  2. import jdk.nashorn.internal.objects.annotations.Getter;
  3. import jdk.nashorn.internal.objects.annotations.Setter;
  4. import javax.persistence.*;
  5. // 该注解目的是为了标记他为一个实体类
  6. @Entity
  7. // 映射数据库中的student表
  8. @Table(name = "student")
  9. public class student {
  10. //标记为主键
  11. @Id
  12. // 申明主键生成策略 自动增长
  13. @GeneratedValue(strategy = GenerationType.IDENTITY)
  14. private Integer id;
  15. // 将此属性与数据库表中的stu_no进行对应
  16. @Column(name = "stu_no")
  17. private String stuNo;
  18. @Column(name = "stu_name")
  19. private String stuName;
  20. @Column(name = "teacher_id")
  21. private String teacherId;
  22. @JoinColumn(name = "teacher_id",insertable = false,updatable = false)
  23. @OneToOne(targetEntity=teacher.class,cascade=CascadeType.DETACH)
  24. private teacher teacher;
  25. public cn.com.demo.springdatajpa.pojo.teacher getTeacher() {
  26. return teacher;
  27. }
  28. public void setTeacher(cn.com.demo.springdatajpa.pojo.teacher teacher) {
  29. this.teacher = teacher;
  30. }
  31. public Integer getId() {
  32. return id;
  33. }
  34. public String getStuNo() {
  35. return stuNo;
  36. }
  37. public String getStuName() {
  38. return stuName;
  39. }
  40. public String getTeacherId() {
  41. return teacherId;
  42. }
  43. public void setId(Integer id) {
  44. this.id = id;
  45. }
  46. public void setStuNo(String stuNo) {
  47. this.stuNo = stuNo;
  48. }
  49. public void setStuName(String stuName) {
  50. this.stuName = stuName;
  51. }
  52. public void setTeacherId(String teacherId) {
  53. this.teacherId = teacherId;
  54. }
  55. @Override
  56. public String toString() {
  57. return "student{" +
  58. "id=" + id +
  59. ", stuNo='" + stuNo + '\'' +
  60. ", stuName='" + stuName + '\'' +
  61. ", teacherId='" + teacherId + '\'' +
  62. ", teacher=" + teacher +
  63. '}';
  64. }
  65. }

我们回到SpringDataJpaApplicationTests中进行测试,用一下代码进行测试

  1. package cn.com.demo.springdatajpa;
  2. import cn.com.demo.springdatajpa.dao.studentDao;
  3. import cn.com.demo.springdatajpa.dao.teacherDao;
  4. import cn.com.demo.springdatajpa.pojo.student;
  5. import cn.com.demo.springdatajpa.pojo.teacher;
  6. import org.junit.jupiter.api.Test;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.boot.test.context.SpringBootTest;
  9. import java.util.List;
  10. @SpringBootTest
  11. class SpringDataJpaApplicationTests {
  12. @Autowired
  13. private studentDao studentDao;
  14. @Test
  15. void contextLoads() {
  16. List<student> students= studentDao.findAll();
  17. for (student stu:students){
  18. System.out.println("学生姓名:"+stu.getStuName()+",他的老师姓名: "+stu.getTeacher().getTeacherName());
  19. }
  20. }
  21. }

测试结果:

我们就可以发现,学生对应的老师姓名,就出来啦。

 好啦,这就是jpa的一对一关联,你是不是发现很简单呢。不需要一条SQL语句就可以轻松实现啦!假如你学废了,看懂的话,给我点个赞哦!爱你!

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号