Hibernate – 一对一映射
前提条件: hibernate框架基础知识,数据库知识, Java
Hibernate 是一个提供一些抽象层的框架,这意味着程序员不必担心实现,Hibernate 会在内部为您完成实现,例如与数据库建立连接、编写查询以执行 CRUD 操作等。用于开发持久性逻辑的Java框架。持久性逻辑意味着存储和处理数据以供长期使用。更准确地说,Hibernate 是一个开源的、非侵入性的、轻量级的Java ORM(对象关系映射)框架,用于开发独立于数据库软件的对象,并在所有Java、JEE 中制作独立的持久化逻辑。
什么是一对一映射?
一对一表示单个实体与另一个实体的单个实例相关联。源实体的一个实例最多可以映射到目标实体的一个实例。我们周围有很多例子来演示这种一对一的映射。
- 一个人有一本护照,一本护照与一个人相关联。
- 豹子有独特的斑点,斑点图案与单个豹子有关。
- 我们有一个大学 ID,一个大学 ID 与一个人唯一关联。
如果你观察,你可以找到更多日常生活的例子。在数据库管理系统中,一对一映射有两种类型——
- 一对一单向
- 一对一双向
一对一单向
在这种类型的映射中,一个实体具有引用目标实体中的属性或列的属性或列。让我们在一个例子的帮助下看到这一点 -
在此示例中,学生表在外键student_gfg_detail_id的帮助下与student_gfg_detail关联,该外键引用student_gfg_detail.id 。目标实体 ( student_gfg_detail ) 无法与学生表关联,但学生表可以在外键的帮助下访问student_gfg_table 。上述关系可以借助以下 SQL 脚本生成。
DROP SCHEMA IF EXISTS `hb-one-to-one-mapping`;
CREATE SCHEMA `hb-one-to-one-mapping`;
use `hb-one-to-one-mapping`;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `student_gfg_detail`;
-- -----------------------------------------------------
-- Table `hb-one-to-one-mapping`.`student_gfg_detail`
-- -----------------------------------------------------
CREATE TABLE `student_gfg_detail` (
`id` INT NOT NULL AUTO_INCREMENT,
`college` varchar(128) DEFAULT NULL,
`no_of_problems_solved` INT DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
DROP TABLE IF EXISTS `instructor`;
-- -----------------------------------------------------
-- Table `hb-one-to-one-mapping`.`student`
-- -----------------------------------------------------
CREATE TABLE `hb-one-to-one-mapping`.`student` (
`id` INT NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(45) NULL DEFAULT NULL,
`last_name` VARCHAR(45) NULL DEFAULT NULL,
`email` VARCHAR(45) NULL DEFAULT NULL,
`student_gfg_detail_id` INT UNIQUE,
PRIMARY KEY (`id`),
FOREIGN KEY (`student_gfg_detail_id`)
REFERENCES `hb-one-to-one-mapping`.`student_gfg_detail` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
SET FOREIGN_KEY_CHECKS = 1;
在创建学生表时,我们引用主键 student_gfg_detail表,即student_gfg_detail.id。我们特意设置了ON DELETE NO ACTION和ON DELETE NO ACTION ,因为我们将在 Hibernate 中设置这些值。现在让我们在 Hibernate 的帮助下将条目添加到数据库中。首先,让我们定义我们的休眠配置文件。
XML
com.mysql.cj.jdbc.Driver
jdbc:mysql://localhost:3306/hb-one-to-one-mapping?useSSL=false&allowPublicKeyRetrieval=true
your_username
your_password
1
org.hibernate.dialect.MySQLDialect
true
thread
XML
4.0.0
com.geeksforgeeks
Hibernate-One-to-One-Mapping
1.0
11
11
org.hibernate
hibernate-vibur
5.6.5.Final
mysql
mysql-connector-java
8.0.28
Java
package com.geeksforgeeks.entity;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "first_name") private String firstName;
@Column(name = "last_name") private String lastName;
@Column(name = "email") private String email;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "student_gfg_detail_id")
private StudentGfgDetail studentGfgDetail;
public Student() {}
public Student(String firstName, String lastName,
String email)
{
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getFirstName() { return firstName; }
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
public String getLastName() { return lastName; }
public void setLastName(String lastName)
{
this.lastName = lastName;
}
public String getEmail() { return email; }
public void setEmail(String email)
{
this.email = email;
}
public StudentGfgDetail getStudentGfgDetail()
{
return studentGfgDetail;
}
public void
setStudentGfgDetail(StudentGfgDetail studentGfgDetail)
{
this.studentGfgDetail = studentGfgDetail;
}
@Override public String toString()
{
return "Student{"
+ "id=" + id + ", firstName='" + firstName
+ '\'' + ", lastName='" + lastName + '\''
+ ", email='" + email + '\''
+ ", studentGfgDetail=" + studentGfgDetail
+ '}';
}
}
Java
package com.geeksforgeeks.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "student_gfg_detail")
public class StudentGfgDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "college") private String college;
@Column(name = "no_of_problems_solved")
private int noOfProblemsSolved;
public StudentGfgDetail() {}
public StudentGfgDetail(String college,
int noOfProblemsSolved)
{
this.college = college;
this.noOfProblemsSolved = noOfProblemsSolved;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getCollege() { return college; }
public void setCollege(String college)
{
this.college = college;
}
public int getNoOfProblemsSolved()
{
return noOfProblemsSolved;
}
public void
setNoOfProblemsSolved(int noOfProblemsSolved)
{
this.noOfProblemsSolved = noOfProblemsSolved;
}
@Override public String toString()
{
return "StudentGfgDetail{"
+ "id=" + id + ", college='" + college + '\''
+ ", noOfProblemsSolved=" + noOfProblemsSolved
+ '}';
}
}
Java
package com.geeksforgeeks.application;
import com.geeksforgeeks.entity.Student;
import com.geeksforgeeks.entity.StudentGfgDetail;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class AddingEntryDemo {
public static void main(String[] args)
{
// Create session factory
SessionFactory factory
= new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.addAnnotatedClass(StudentGfgDetail.class)
.buildSessionFactory();
// Create session
try (factory; Session session
= factory.getCurrentSession()) {
// Get the current session
// Create relevant object.
Student student = new Student("Vyom", "Yadav",
"vyom@gmail.com");
StudentGfgDetail studentGfgDetail
= new StudentGfgDetail("GFG College", 20);
student.setStudentGfgDetail(studentGfgDetail);
// Begin the transaction
session.beginTransaction();
// Save the student object.
// This will also save the StudentGfgDetail
// object as we have used CascadeType.ALL
session.save(student);
// Commit the transaction
session.getTransaction().commit();
System.out.println(
"Transaction Successfully Completed!");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Java
package com.geeksforgeeks.application;
import com.geeksforgeeks.entity.Student;
import com.geeksforgeeks.entity.StudentGfgDetail;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class UpdateEntryDemo {
public static void main(String[] args)
{
// Create session factory
SessionFactory factory
= new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.addAnnotatedClass(StudentGfgDetail.class)
.buildSessionFactory();
// Create session
try (factory; Session session
= factory.getCurrentSession()) {
// Begin the transaction
session.beginTransaction();
// Get object with id = 1
int id = 1;
Student student
= session.get(Student.class, id);
StudentGfgDetail studentGfgDetail
= student.getStudentGfgDetail();
// modify the student and its details
student.setEmail("vyom@geeksforgeeks.com");
studentGfgDetail.setNoOfProblemsSolved(40);
// Update the student object.
// This will also update the StudentGfgDetail
// object as we have used CascadeType.ALL
session.update(student);
// Commit the transaction
session.getTransaction().commit();
System.out.println(
"Transaction Successfully Completed!");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Java
package com.geeksforgeeks.entity;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "student_gfg_detail")
public class StudentGfgDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "college") private String college;
@Column(name = "no_of_problems_solved")
private int noOfProblemsSolved;
@OneToOne(mappedBy = "studentGfgDetail",
cascade = CascadeType.ALL)
private Student student;
public StudentGfgDetail() {}
public StudentGfgDetail(String college,
int noOfProblemsSolved)
{
this.college = college;
this.noOfProblemsSolved = noOfProblemsSolved;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getCollege() { return college; }
public void setCollege(String college)
{
this.college = college;
}
public int getNoOfProblemsSolved()
{
return noOfProblemsSolved;
}
public void
setNoOfProblemsSolved(int noOfProblemsSolved)
{
this.noOfProblemsSolved = noOfProblemsSolved;
}
public Student getStudent() { return student; }
public void setStudent(Student student)
{
this.student = student;
}
@Override public String toString()
{
return "StudentGfgDetail{"
+ "id=" + id + ", college='" + college + '\''
+ ", noOfProblemsSolved=" + noOfProblemsSolved
+ ", student=" + student + '}';
}
}
Java
package com.geeksforgeeks.application;
import com.geeksforgeeks.entity.Student;
import com.geeksforgeeks.entity.StudentGfgDetail;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class AddEntryBidirectionalDemo {
public static void main(String[] args)
{
// Create session factory
SessionFactory factory
= new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.addAnnotatedClass(StudentGfgDetail.class)
.buildSessionFactory();
// Create session
try (factory; Session session
= factory.getCurrentSession()) {
// Create relevant object.
Student student = new Student("JJ", "Olatunji",
"jj@gmail.com");
StudentGfgDetail studentGfgDetail
= new StudentGfgDetail("GFG College", 0);
student.setStudentGfgDetail(studentGfgDetail);
studentGfgDetail.setStudent(student);
// Begin the transaction
session.beginTransaction();
// Save the studentGfgDetail object.
// This will also save the student object as we
// have used CascadeType.ALL
session.save(studentGfgDetail);
// Commit the transaction
session.getTransaction().commit();
System.out.println(
"Transaction Successfully Completed!");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Java
package com.geeksforgeeks.application;
import com.geeksforgeeks.entity.Student;
import com.geeksforgeeks.entity.StudentGfgDetail;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class ReadEntryBidirectionalDemo {
public static void main(String[] args)
{
// Create session factory
SessionFactory factory
= new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.addAnnotatedClass(StudentGfgDetail.class)
.buildSessionFactory();
// Create session
try (factory; Session session
= factory.getCurrentSession()) {
// Begin the transaction
session.beginTransaction();
int theId = 5;
StudentGfgDetail studentGfgDetail = session.get(
StudentGfgDetail.class, theId);
System.out.println(
studentGfgDetail.getStudent());
System.out.println(studentGfgDetail);
// Commit the transaction
session.getTransaction().commit();
System.out.println(
"Transaction Successfully Completed!");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
我们将使用 MySQL 作为 JDBC 驱动程序。您也可以使用任何其他供应商实现。在配置文件中,我们使用数据库连接设置、连接池设置、SQL 方言等设置会话工厂。这里要注意的一个重要属性是current_session_context_class 。大多数使用 Hibernate 的应用程序需要某种形式的“上下文”会话,其中给定的会话在给定上下文的整个范围内都有效。此处此属性指定当前会话仅在一个线程的上下文中。另外不要忘记将your_username更改为您的数据库用户名,将your_password更改为您的数据库密码。
现在我们需要将休眠 JAR 文件和 MySQL 数据库连接器添加到我们的外部库中。我将使用 maven 添加这些 JAR 文件,但您也可以从官方来源下载它们并手动将它们添加到您的外部库中。让我们定义我们的pom.xml文件
XML
4.0.0
com.geeksforgeeks
Hibernate-One-to-One-Mapping
1.0
11
11
org.hibernate
hibernate-vibur
5.6.5.Final
mysql
mysql-connector-java
8.0.28
现在我们已经添加了相关的依赖项,让我们从定义我们的实体开始。
Java
package com.geeksforgeeks.entity;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "first_name") private String firstName;
@Column(name = "last_name") private String lastName;
@Column(name = "email") private String email;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "student_gfg_detail_id")
private StudentGfgDetail studentGfgDetail;
public Student() {}
public Student(String firstName, String lastName,
String email)
{
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getFirstName() { return firstName; }
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
public String getLastName() { return lastName; }
public void setLastName(String lastName)
{
this.lastName = lastName;
}
public String getEmail() { return email; }
public void setEmail(String email)
{
this.email = email;
}
public StudentGfgDetail getStudentGfgDetail()
{
return studentGfgDetail;
}
public void
setStudentGfgDetail(StudentGfgDetail studentGfgDetail)
{
this.studentGfgDetail = studentGfgDetail;
}
@Override public String toString()
{
return "Student{"
+ "id=" + id + ", firstName='" + firstName
+ '\'' + ", lastName='" + lastName + '\''
+ ", email='" + email + '\''
+ ", studentGfgDetail=" + studentGfgDetail
+ '}';
}
}
Java
package com.geeksforgeeks.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "student_gfg_detail")
public class StudentGfgDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "college") private String college;
@Column(name = "no_of_problems_solved")
private int noOfProblemsSolved;
public StudentGfgDetail() {}
public StudentGfgDetail(String college,
int noOfProblemsSolved)
{
this.college = college;
this.noOfProblemsSolved = noOfProblemsSolved;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getCollege() { return college; }
public void setCollege(String college)
{
this.college = college;
}
public int getNoOfProblemsSolved()
{
return noOfProblemsSolved;
}
public void
setNoOfProblemsSolved(int noOfProblemsSolved)
{
this.noOfProblemsSolved = noOfProblemsSolved;
}
@Override public String toString()
{
return "StudentGfgDetail{"
+ "id=" + id + ", college='" + college + '\''
+ ", noOfProblemsSolved=" + noOfProblemsSolved
+ '}';
}
}
如今所有最新的框架都严重依赖注释,因为它使代码更短且更易于理解,让我们逐步了解正在发生的事情。当我们将Student对象和StudentGfgDetail对象存储在数据库中时,我们用@Entity注释它们。 @Table注解指定与实体关联的主表,我们在注解内传递表的名称。
- @Id – 指定给定字段是实体的主键。
- @GeneratedValue - 这定义了生成主键的策略,这里我们使用GenerationType.IDENTITY自动增加 Id 的值,如果我们不想使用它,我们必须在每次创建时显式指定主键一个东西。
- @Column - 这只是将给定字段映射到数据库内的列。
这里要注意的关键是以下部分-
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "student_gfg_detail_id")
private StudentGfgDetail studentGfgDetail;
我们在Student类中添加了一个StudentGfgDetail对象,该对象使用@OneToOne注释进行注释,该注释指定一对一映射。此注释包含一个名为cascade的元素,它指定级联策略。级联是一种功能,用于在父实体的状态发生变化时管理目标实体的状态。基本的 Hibernate 级联类型是-
- CascadeType.ALL – 将所有操作从父实体传播到目标实体。
- CascadeType.PERSIST – 从父实体持续传播到目标实体。
- CascadeType.MERGE – 从父实体传播合并到目标实体。
- CascadeType.REMOVE – 将删除从父实体传播到目标实体。
- CascadeType.REFRESH – 将刷新从父实体传播到目标实体。
- CascadeType.DETACH – 将分离从父实体传播到目标实体。
例如,如果cascade = CascadeType.REMOVE那么如果父实体从数据库中删除,那么目标实体也将从数据库中删除,即如果学生实体从数据库中删除,则相关的StudentGfgDetail将自动删除。手术。 @JoinColumn注释指定用于连接目标实体的列。这里指定StudentGfgDetail应该加入到student_gfg_detail_id列,这是正确的,因为student_gfg_detail_id作为我们的外键。
这建立了一对一的单向关系,因为Student可以访问StudentGfgDetail实体,但反之则不然。现在,在我们完成实体的定义之后,让我们开始实际行动,让我们在 hibernate 的帮助下修改我们的数据库。让我们在我们的数据库中添加一个条目-
Java
package com.geeksforgeeks.application;
import com.geeksforgeeks.entity.Student;
import com.geeksforgeeks.entity.StudentGfgDetail;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class AddingEntryDemo {
public static void main(String[] args)
{
// Create session factory
SessionFactory factory
= new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.addAnnotatedClass(StudentGfgDetail.class)
.buildSessionFactory();
// Create session
try (factory; Session session
= factory.getCurrentSession()) {
// Get the current session
// Create relevant object.
Student student = new Student("Vyom", "Yadav",
"vyom@gmail.com");
StudentGfgDetail studentGfgDetail
= new StudentGfgDetail("GFG College", 20);
student.setStudentGfgDetail(studentGfgDetail);
// Begin the transaction
session.beginTransaction();
// Save the student object.
// This will also save the StudentGfgDetail
// object as we have used CascadeType.ALL
session.save(student);
// Commit the transaction
session.getTransaction().commit();
System.out.println(
"Transaction Successfully Completed!");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
现在让我们逐步讨论这个问题-
- 我们在配置文件的帮助下创建会话工厂,因为我们在配置文件中设置了详细信息。然后我们添加注释类,基本上是我们在前面的步骤中注释的类,然后构建会话工厂。
- 从会话工厂获取当前会话。
- 创建相关对象并调用 setter 方法。
- 开始交易。
- 保存Student对象,这也保存了关联的StudentGfgDetail ,因为我们在前面的步骤中使用了CascadeType.ALL 。
- 获取事务并提交更改。
- 关闭当前会话。
- 关闭会话工厂,因为我们不想创建更多会话。
如果我们以正确的配置运行上面的代码,我们应该会看到类似的输出 -
输出可能不是 100% 相同,因为它取决于您使用的休眠版本,但它应该非常接近上面的输出。让我们仔细检查这些值是否已插入数据库。
现在我们已经验证我们能够向数据库添加一个条目并且我们的操作正在运行,让我们尝试更新这些条目。
Java
package com.geeksforgeeks.application;
import com.geeksforgeeks.entity.Student;
import com.geeksforgeeks.entity.StudentGfgDetail;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class UpdateEntryDemo {
public static void main(String[] args)
{
// Create session factory
SessionFactory factory
= new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.addAnnotatedClass(StudentGfgDetail.class)
.buildSessionFactory();
// Create session
try (factory; Session session
= factory.getCurrentSession()) {
// Begin the transaction
session.beginTransaction();
// Get object with id = 1
int id = 1;
Student student
= session.get(Student.class, id);
StudentGfgDetail studentGfgDetail
= student.getStudentGfgDetail();
// modify the student and its details
student.setEmail("vyom@geeksforgeeks.com");
studentGfgDetail.setNoOfProblemsSolved(40);
// Update the student object.
// This will also update the StudentGfgDetail
// object as we have used CascadeType.ALL
session.update(student);
// Commit the transaction
session.getTransaction().commit();
System.out.println(
"Transaction Successfully Completed!");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
我们需要理解的唯一一段代码是——
// Get object with id = 1
int id = 1;
Student student = session.get(Student.class, id);
StudentGfgDetail studentGfgDetail = student.getStudentGfgDetail();
// modify the student and its details
student.setEmail("vyom@geeksforgeeks.com");
studentGfgDetail.setNoOfProblemsSolved(40);
// Update the student object.
// This will also update the StudentGfgDetail object as we have used CascadeType.ALL
session.update(student);
- 我们得到 id = 1 的学生。
- 修改细节。
- 更新值。
这里要注意的一点是,我们应该在里面使用get(Student.class, id)方法,这就是为什么这段代码是在我们开始事务之后出现的。如果我们以正确的配置运行代码,则输出 -
同样,输出取决于休眠版本,但应该相似。我们还可以在数据库中验证这些更改——
从数据库中读取值也可以很容易地完成,只需将开始事务下的部分修改为-
// Get object with id = 1
int id = 1;
Student student = session.get(Student.class, id);
StudentGfgDetail studentGfgDetail = student.getStudentGfgDetail();
System.out.println(student);
System.out.println(studentGfgDetail);
// Commit the transaction
session.getTransaction().commit();
// close the session
session.close();
我们可以根据需要将数据打印到标准输出流或文件中。请注意,不需要保存,因为我们没有修改数据,我们只是在读取它。删除也可以类似地进行——
// Get object with id = 1
int id = 1;
Student student = session.get(Student.class, id);
// Delete the student, this will also delete the associated entity
// as we use CascadeType.ALL
session.delete(student);
// Commit the transaction
session.getTransaction().commit();
// close the session
session.close();
请注意,关联的StudentGfgDetail实体也将被删除,因为我们正在使用CascadeType.ALL
一对一双向
到目前为止,这种关系是单向的,即我们可以从以下位置访问StudentGfgDetail Student实体,反之亦然,但是为什么我们要建立双向关系,单向关系有什么问题?
问题:
如果我们以某种方式删除StudentGfgDetail实体并让Student实体保持原样,那么 Student 实体将有一个外键引用一个不存在的对象,这会引入悬空外键的问题,这当然是一种不好的做法.删除StudentGfgDetail实体时删除Student实体的选项取决于数据库的设计,我们可能希望将Student实体保留为离开社区的用户的记录,或者只是删除它。幸运的是,我们可以在不修改数据库的情况下实现上述两件事,并且仅在 Hibernate 的帮助下,只需修改StudentGfgDetail。Java-
Java
package com.geeksforgeeks.entity;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "student_gfg_detail")
public class StudentGfgDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "college") private String college;
@Column(name = "no_of_problems_solved")
private int noOfProblemsSolved;
@OneToOne(mappedBy = "studentGfgDetail",
cascade = CascadeType.ALL)
private Student student;
public StudentGfgDetail() {}
public StudentGfgDetail(String college,
int noOfProblemsSolved)
{
this.college = college;
this.noOfProblemsSolved = noOfProblemsSolved;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getCollege() { return college; }
public void setCollege(String college)
{
this.college = college;
}
public int getNoOfProblemsSolved()
{
return noOfProblemsSolved;
}
public void
setNoOfProblemsSolved(int noOfProblemsSolved)
{
this.noOfProblemsSolved = noOfProblemsSolved;
}
public Student getStudent() { return student; }
public void setStudent(Student student)
{
this.student = student;
}
@Override public String toString()
{
return "StudentGfgDetail{"
+ "id=" + id + ", college='" + college + '\''
+ ", noOfProblemsSolved=" + noOfProblemsSolved
+ ", student=" + student + '}';
}
}
我们在这里唯一需要介绍的是——
@OneToOne(mappedBy = "studentGfgDetail",
cascade = CascadeType.ALL)
private Student student;
现在我们的student_gfg_detail表中没有引用学生表的列,那么这段代码是什么?
这就是 Hibernate 帮助我们的地方, mappedBy = “studentGfgDetail”告诉我们 休眠以在 Student 类中查找名为studentGfgDetail的字段,并将该特定实例链接到当前的学生对象。现在我们已经了解了链接,让我们尝试在数据库中添加一个条目,但这次我们将显式保存StudentGfgDetail对象,由于CascadeType.ALL ,这也将隐式保存相关的Student对象。
Java
package com.geeksforgeeks.application;
import com.geeksforgeeks.entity.Student;
import com.geeksforgeeks.entity.StudentGfgDetail;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class AddEntryBidirectionalDemo {
public static void main(String[] args)
{
// Create session factory
SessionFactory factory
= new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.addAnnotatedClass(StudentGfgDetail.class)
.buildSessionFactory();
// Create session
try (factory; Session session
= factory.getCurrentSession()) {
// Create relevant object.
Student student = new Student("JJ", "Olatunji",
"jj@gmail.com");
StudentGfgDetail studentGfgDetail
= new StudentGfgDetail("GFG College", 0);
student.setStudentGfgDetail(studentGfgDetail);
studentGfgDetail.setStudent(student);
// Begin the transaction
session.beginTransaction();
// Save the studentGfgDetail object.
// This will also save the student object as we
// have used CascadeType.ALL
session.save(studentGfgDetail);
// Commit the transaction
session.getTransaction().commit();
System.out.println(
"Transaction Successfully Completed!");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
请注意,我们没有任何键引用 student_gfg_detail表中的学生仍然存在,我们可以通过StudentGfgDetail对象保存它。
输出:
我们可以看到 hibernate 进行了两次插入,所以我们知道这两个值都已成功插入,现在让我们尝试通过检索StudentGfgDetail对象来读取这些值。
Java
package com.geeksforgeeks.application;
import com.geeksforgeeks.entity.Student;
import com.geeksforgeeks.entity.StudentGfgDetail;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class ReadEntryBidirectionalDemo {
public static void main(String[] args)
{
// Create session factory
SessionFactory factory
= new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.addAnnotatedClass(StudentGfgDetail.class)
.buildSessionFactory();
// Create session
try (factory; Session session
= factory.getCurrentSession()) {
// Begin the transaction
session.beginTransaction();
int theId = 5;
StudentGfgDetail studentGfgDetail = session.get(
StudentGfgDetail.class, theId);
System.out.println(
studentGfgDetail.getStudent());
System.out.println(studentGfgDetail);
// Commit the transaction
session.getTransaction().commit();
System.out.println(
"Transaction Successfully Completed!");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
如我们所见,我们只是检索了StudentGfgDetail对象,而该对象又隐式检索了Student对象。
输出:
Note: Before retrieving any item from the database, double-check the ID of the Student or StudentGfgDetail as it can vary in different systems due to the number of runs.
我们可以更新和删除项目,就像我们在单向中所做的一样,但要注意现在更新或删除任何实体也会删除关联的实体!