关系型映射---Java持久化API(4) àì夳堔傛蜴生んèń 2021-09-01 03:16 246阅读 0赞 # 关系型映射开发 # ## 1.认识实体间关系映射 ## 对象关系映射(object relational mapping)是指通过将对象状态映射到数据库列,来开发和维护对象和关系数据库之间的关系。它能够轻松处理(执行)各种数据库操作。如插入、更新、删除等。 1. 映射方向 PRM的映射方向是表与表的关联(join),可分为两种。 * 单向关系:代表一个实体可以将属性引用到另一个实体。即只能从A表向B表进行连表查询。 * 双向关系: 代表每个实体都有一个关系字段(属性)引用了其他实体。 1. ORM映射类型 * 一对一(@OneToOne):实体的每个实体与另一个实体的单个实体相关联。 * 一对多(@OneToMany):一个实体的实例可以与另一个实体的多个实例相关联。 * 多对一(@ManyToOne):一个实体的多个实例可以与另一个实体的单个实例相关联。 * 多对多(@ManyToMany):一个实体的多个实例可能与另一个实体的多个实例有关。在这个映射中,任何一方都可以成为所有者方。 ## 实例:实现“一对一”映射 ## 一对一映射首先要确定实体间的关系,并考虑表结构,还要考虑实体关系的方向性。 若为双向关联,则在保存实体关系的实体中要配合注解@JoinColumn。在没有保存实体关系的实体中,要用mappedBy属性明确所关联的实体。 1.编写实体 (1)新建Student实体, @Entity @Data @Table(name = "stdu") public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String name; @Column(columnDefinition = "enum('male','female')") private String sex; /** * Description: * 建立集合,指定关系是一对一,并且申明它在cart类中的名称 * 关联的表为card表,其主键是id * 指定外键名为card_id */ @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "card_id") private Card card; } (2)新建Card实体 @Entity @Table(name = "card") @Data public class Card { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private Integer num; } 2.编写Repository层 (1)编写Student实体的Repository public interface StudentRepository extends JpaRepository<Student, Long> { Student findById(long id); Student deleteById(long id); @Query("select a from Student a where a.name = ?1") Student getStudentByMySelf(String name); @Query(value = "select * from stdu a where a.name = ?1",nativeQuery = true) Student getStudentByMySelf2(String name); @Modifying @Transactional @Query(value = "update Student a set a.name = '龙淘宝' where a.id =:id") void updataUserByGuid(@Param("id") long id); @Modifying @Transactional @Query(value = "update Student a set a.name = :name where a.id =:id") void updataStudentById(@Param("name") String name, @Param("id") long id); } (2)编写Card实体Repository public interface CardRepository extends JpaRepository<Card,Long> , JpaSpecificationExecutor<Card> { Card findById(long id); } 3.编写service (1)编写Student的Service层 public interface StudentService { public List<Student> getStudentlist(); public Student findStudentById(long id); } (2)编写Card的Service层 public interface CardService { public List<Card> getCardList(); public Card findCardById(long id); } 4.编写Service的实现 (1).编写Student实体的Serevice实现 public class StudentServiceImpl implements StudentService { @Autowired private StudentRepository studentRepository; @Override public List<Student> getStudentlist() { return studentRepository.findAll(); } @Override public Student findStudentById(long id) { return studentRepository.findById(id); } } (2)编写Card实体的Service实现 public class CardServiceImpl implements CardService { @Autowired private CardRepository cardRepository; @Override public List<Card> getCardList() { return cardRepository.findAll(); } @Override public Card findCardById(long id) { return cardRepository.findById(id); } } 5.application.properties配置 spring.datasource.url=jdbc:mysql://127.0.0.1/book?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.jpa.properties.hibernate.hbm2ddl.auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.show-sql= true spring.thymeleaf.cache=false server.port=8080 6.编写测试 @SpringBootTest @RunWith(SpringRunner.class) public class oneToOneTest { @Autowired private StudentRepository studentRepository; @Autowired private CardRepository cardRepository; @Test public void testOneToOne() { Student student1 = new Student(); student1.setName("赵大伟"); student1.setSex("male"); Student student2 = new Student(); student2.setName("赵大宝"); student2.setSex("male"); Card card1 = new Card(); card1.setNum(422802); student1.setCard(card1); studentRepository.save(student1); studentRepository.save(student2); Card card2 = new Card(); card2.setNum(422803); cardRepository.save(card2); /** * Description: 获取添加之后的id */ Long id = student1.getId(); /** * Description: 删除刚刚添加的student1 */ studentRepository.deleteById(id); } } ## 总结 ## 对于双向的“一对一”关系映射,发出端和接收端都要使用注解@OneToOne,同时定义一个接收端类型的字段属性和@OneToOne注解中的“mappedBy”属性。这个在双向关系的接受端是必须的。在双向关系中,有一方为关系的发出端,另一方是关系的反端。即“Invaese”端(接受端) ## 实例:实现“一对多”映射 ## 单向关系的一对多注解@OneToMany,只用于关系的发出端(“一”的一方)。另外,需要关系的发出端定义一个集合类型的接受端的字段属性 在一对多关联关系映射中,默认是以中间表方式来映射这种关系的。中间表的名称为“用下画连接关系的拥有端(发出端)和Invaese端(接受端)”,中间表两个字段分别为两张表的表名加下画线“\_”再加主键组成。 当然,也可以改变这种默认的中间件表的映射方式。在关系的拥有端,使用@JoinColumn注解定义外键来映射这个关系 1.编写实体 下面以学校(School)和老师(Teacher)来演示一对多的映射关系。 (1)@OneToMany中One的一方 ------School @Entity @Data public class School { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String name; // @OneToMany(cascade = CascadeType.ALL) @OneToMany() @JoinColumn(name = "school_id") private List<Teacher> teacherList; } (2)@OneToMany中Many的一方------Teacher @Data @Entity public class Teacher { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String name; @ManyToOne private School school; } 2.测试映射关系 Service和Repository层在前面已经讲过了,这里并没有区别,所以不再讲解。 @SpringBootTest @RunWith(SpringRunner.class) public class OneToManyTest { @Autowired private SchoolRepository schoolRepository; @Autowired private TeacherRepository teacherRepository; @Test public void add() { School school1 = new School(); school1.setName("清华大学"); schoolRepository.save(school1); Teacher teacher = new Teacher(); teacher.setName("long"); teacher.setSchool(school1); teacherRepository.save(teacher); } @Test public void find() { School school1 = new School(); school1 = schoolRepository.findSchoolById(3); List<Teacher> teacherList = school1.getTeacherList(); System.out.println(school1.getName()); for (Teacher teacher : teacherList) { System.out.println(teacher.getName()); } } @Test public void deleteSchoolById() { schoolRepository.deleteById(3); } @Test public void deleteTeacherById() { teacherRepository.deleteById(7); } } 在双向一对多关系中,注解@OneToMany(mappedBy=“发出端实体名称小写”)用于关系的发出端(即“One”的一方),同时关系的发出端需要定义一个集合类型的接收端的字段属性;注解@ManyToOne用于关系的接收端(即“Many”的一方),关系的接收端需要定义一个发出端的字段属性 ## 实现“多对多”映射 ## 在“多对多”关联关系中,只能通过中间表的方式进行映射,不能通过增加外键来实现。 注解@ManyToMany用于关系的发出端和接收端。关系的发出端定义一个集合类型的接收端的字段属性,关系的接收端不需要做任何定义 1.创建实体 (1)创建Student实体。 @Entity @Data public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String name; @Column(columnDefinition = "enum('male','female')") private String sex; @ManyToMany(fetch=FetchType.LAZY) @JoinTable(name="teacher_student",joinColumns={@JoinColumn(name="s_id")},inverseJoinColumns={@JoinColumn(name="t_id")}) private Set<Teacher> teachers; } (2)创建Teacher实体 @Data @Entity public class Teacher { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String name; @ManyToMany(fetch=FetchType.LAZY) /** * Description: * 1、关系两边都作为主控; * 2、joinColumns中@JoinColumn(name="t_id") 其中t_id为JoinTable 中的外键,由于 Student 和Teacher 的主键都为id 这边就省略referencedColumnName="id"。 */ @JoinTable(name="teacher_student",joinColumns={@JoinColumn(name="t_id")},inverseJoinColumns={@JoinColumn(name="s_id")}) private Set<Student> students; } **在多对多关系中需要注意以下几点** * 关系的双方都可以作为主控 * 在joinColumns的@JoinColumn(name=“t\_id”)中,t\_id为JoinTable中的外键。由于Student和Teacher的主键都为id,所以这里省略了referencedColumnName=“id”。 * 在设计模型之间的级联关系时,要考虑好应该采用何种级联规则。 * 如果设置cascade = CascadeType.PERSIST,则在执行save时会调用onPersist()方法。这个方法会递归调用外联类(Student或Teacher)的onPersist()进行级联新增。但因为值已经添加了,所以会报detached entity passed to persist错误,将级联操作取消(去掉“cascade = CascadeType.PERSIST”)即可。 2.创建测试 由于Service和Pepository与上述代码中的一样,这里不多做重复 @SpringBootTest @RunWith(SpringRunner.class) public class ManyToManyTest { @Autowired private StudentRepository studentRepository; @Autowired private TeacherRepository teacherRepository; @Test public void add() { Set<Teacher> teachers = new HashSet<>(); Set<Student> students = new HashSet<>(); Student student1 = new Student(); student1.setName("zhonghua"); students.add(student1); studentRepository.save(student1); Student student2 = new Student(); student2.setName("zhiran"); students.add(student2); studentRepository.save(student2); Teacher teacher1 =new Teacher(); teacher1.setName("龙老师"); teacher1.setStudents(students); teachers.add(teacher1); teacherRepository.save(teacher1); } } 对于双向ManyToMany关系,注解@ManyToMany用于关系的发出端和接受端。另外,关系的接受端需要设置@ManyToMany(mappedBy=‘集合类型发出端实体的字段名称’) -------------------- 文章介选《SpringBoot实战派》 -------------------- 到这里 关系Java持久化的API–JPA就要告一段落了。文章不易 看到请多多点赞!!!
相关 数据持久化:Java对象关系映射(ORM)策略与实践案例 在Java开发中,数据持久化是将对象的状态保存到持久存储介质的过程。常见的持久化方式是使用对象关系映射(ORM)技术。 1. **Hibernate**:一个流行的开源ORM 梦里梦外;/ 2024年09月11日 17:12/ 0 赞/ 10 阅读
相关 HarmonyOS 数据持久化 关系型数据库之 查询逻辑编写 但是 这里 我们还需要对查询结果做解析 那么 我们需要定义一个类 来记录我们表的数据结构类型。我们已经编写了 初始化 和 增删改 操作的基本逻辑 最后 收尾一下... 小鱼儿/ 2024年04月22日 07:49/ 0 赞/ 21 阅读
相关 HarmonyOS 数据持久化 关系型数据库之 增删改逻辑编写 然后 我们在 initTaskDB 下面再定义一个函数 叫 addTask 的函数 用来执行添加逻辑。然后 用 predicates 对象调用 equalTo ... 青旅半醒/ 2024年04月22日 07:48/ 0 赞/ 26 阅读
相关 HarmonyOS 数据持久化 关系型数据库之 初始化操作 relationalStore.getRdbStore 获取 rdbSore 需要两个参数 UIAbility上下文的 ConText 和 我们上面声明的confi... 快来打我*/ 2024年04月22日 07:47/ 0 赞/ 36 阅读
相关 持久化API(JPA)系列(六)实体关系映射(ORM)之映射类型 ORM实体关系映射,即将数据库中的数据表及表之间的关系,通过实体Bean及实体Bean之间的关系表现出来,实现通过操作实体Bean来操作数据库。 墨蓝/ 2022年08月08日 03:24/ 0 赞/ 131 阅读
相关 持久化API(JPA)系列(七)实体关系映射(ORM)之单表映射@IdClass 通过以前的文章,我们了解到@Table、@Column、@Id实现了单表的映射,并且书剑有一个@Id指定的唯一字段。有时我们的数据表也许是有多个主键联合组成的,因 系统管理员/ 2022年08月05日 12:12/ 0 赞/ 218 阅读
相关 持久层框架-关系映射框架(ORM) 文章目录 jdbc 谈谈Hibernate与Ibatis的区别 Hibernate Mybatis ゝ一纸荒年。/ 2022年05月08日 00:16/ 0 赞/ 254 阅读
相关 认识JPA---Java持久化API(1) 认识JPA 认识ORM 认识Spring Data 主要模块 社区模块 认识JPA 使用JPA 了解JPA注解和属 柔情只为你懂/ 2021年09月01日 04:40/ 0 赞/ 323 阅读
相关 关系型映射---Java持久化API(4) 关系型映射开发 1.认识实体间关系映射 对象关系映射(object relational mapping)是指通过将对象状态映射到数据库列,来开发和维护对象 àì夳堔傛蜴生んèń/ 2021年09月01日 03:16/ 0 赞/ 247 阅读
还没有评论,来说两句吧...