Hibernate – 多对多映射
在 RDBMS 中,我们可以看到非常常见的父子关系用法。它可以通过在 Hibernate 中实现
- 一对多关系
- 多对一关系
- 一对一的关系
- 多对多关系
在这里,我们将讨论如何执行 Hibernate –多对多映射。下面是演示多对多映射的示例表,如下所示:
- 极客员工数据
- 技能组数据
- 极客员工技能
执行:
A、建表步骤如下:
-- Table containing employeedata
create table geeksforgeeks.geekEmployeeData (
id INT NOT NULL auto_increment,
firstName VARCHAR(20) default NULL,
lastName VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
-- Table containing skillsets
create table geeksforgeeks.SkillsetData (
id INT NOT NULL auto_increment,
skillName VARCHAR(30) default NULL,
PRIMARY KEY (id)
);
-- Table which can combine employeedata and skillsets
create table geekEmployeeSkill (
geekEmpId INT NOT NULL,
skillId INT NOT NULL,
PRIMARY KEY (geekEmpId,skillId)
);
必须使用 Set Java集合来实现多对多映射,并且它不应包含任何重复元素。 Set 可以与映射表中的
B. POJO 类
对于 geekEmployeeData 表数据 CRUD 操作,这是必需的
例子:
Java
// Java Program to Illustrate GeekEmployeeData Class
// Importing required classes
import java.util.Set;
// Class
public class GeekEmployeeData {
// Attributes are mapping to geekEmployeeData
// geekEmployeeData.id
private int id;
// geekEmployeeData.firstName
private String firstName;
// geekEmployeeData.lastName
private String lastName;
// geekEmployeeData.salary
private int salary;
// Collection of skillsets in Set variable
private Set skillSets;
// Method
public Set getSkillSets() { return skillSets; }
public void setSkillSets(Set skillSets)
{
// This keyword refers to current instance itself
this.skillSets = skillSets;
}
// Constructor 1
public GeekEmployeeData() {}
// Constructor 2
public GeekEmployeeData(String firstName,
String lastName, int salary)
{
// This keyword refers to current instance itself
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
}
// Getter and Setters
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 int getSalary() { return salary; }
public void setSalary(int salary)
{
this.salary = salary;
}
}
Java
public class SkillsetData {
private int id;
private String skillName;
public SkillsetData() {}
public SkillsetData(String skillName)
{
this.skillName = skillName;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getSkillName() { return skillName; }
public void setSkillName(String skillName)
{
this.skillName = skillName;
}
public boolean equals(Object obj)
{
// This method is definitely required in order to
// check whether any two elements/objects are equal
if (obj == null)
return false;
if (!this.getClass().equals(obj.getClass()))
return false;
SkillsetData obj2 = (SkillsetData)obj;
if ((this.id == obj2.getId())
&& (this.skillName.equals(
obj2.getSkillName()))) {
return true;
}
return false;
}
// collections calculate the hash value for a given key
// using the hashCode() method.
public int hashCode()
{
// This method is definitely required in order to
// check whether any two elements/objects are equal
int tmp = 0;
tmp = (id + skillName).hashCode();
return tmp;
}
}
XML
This class contains the geekEmployeeData detail.
This class contains the skillset records.
XML
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/geeksforgeeks
root
xxxx
org.hibernate.dialect.MySQLDialect
true
true
update
Java
// Java Program to Illustrate GeekEmployeeManytoManyExample
// Class
// Importing required classes
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.Restrictions;
// Class
public class GeekEmployeeManytoManyExample {
// Class data member
private static SessionFactory factory;
// Main driver method
public static void main(String[] args)
{
// Try block to check for exceptions
try {
factory = new Configuration()
.configure()
.buildSessionFactory();
}
// Catch block to handle exceptions
catch (Throwable ex) {
// Display command when exception occurred
System.err.println(
"Failed to create sessionFactory object."
+ ex);
throw new ExceptionInInitializerError(ex);
}
GeekEmployeeManytoManyExample geekEmployeeObject
= new GeekEmployeeManytoManyExample();
// Let us have a set of skills for few employees
HashSet skillSets = new HashSet();
skillSets.add(new SkillsetData("Java"));
skillSets.add(new SkillsetData("Python"));
skillSets.add(new SkillsetData("R Programming"));
HashSet databaseSkillSets = new HashSet();
databaseSkillSets.add(new SkillsetData("MySQL"));
databaseSkillSets.add(
new SkillsetData("SQL Server"));
databaseSkillSets.add(new SkillsetData("MongoDB"));
HashSet generalSkillset = new HashSet();
generalSkillset.add(skillSets);
generalSkillset.add(databaseSkillSets);
// Add few employee records in database
Integer empID1 = geekEmployeeObject.addEmployee(
"GeekA", "GeekA", 100000, skillSets);
Integer empID2 = geekEmployeeObject.addEmployee(
"GeekB", "GeekB", 50000, databaseSkillSets);
Integer empID3 = geekEmployeeObject.addEmployee(
"GeekC", "GeekC", 50000, skillSets);
}
/* Method to CREATE an employee in the database. Inserts
data in
geekEmployeeData, SkillsetData and geekEmployeeSkill table
*/
public Integer addEmployee(String fname, String lname,
int salary, Set skillSets)
{
Session session = factory.openSession();
Transaction tx = null;
Integer employeeID = null;
try {
tx = session.beginTransaction();
GeekEmployeeData employee
= new GeekEmployeeData(fname, lname,
salary);
employee.setSkillSets(skillSets);
employeeID = (Integer)session.save(employee);
tx.commit();
}
catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
}
// finally block
finally {
// Closing the sessions
// using close() method
session.close();
}
return employeeID;
}
}
Java
// Java Program to List the Records by
// Using Hibernate Criteria Query
// Method
public void listGeekEmployeeData()
{
Session session = factory.openSession();
Transaction tx = null;
// Try block to check for exceptions
try {
tx = session.beginTransaction();
Criteria geekEmployeeCriteria
= session.createCriteria(
GeekEmployeeData.class);
List geekEmployeeList = geekEmployeeCriteria.list();
for (Iterator iterator
= geekEmployeeList.iterator();
iterator.hasNext();) {
GeekEmployeeData employeeData
= (GeekEmployeeData)iterator.next();
System.out.print("First Name: "
+ employeeData.getFirstName());
System.out.print(" Last Name: "
+ employeeData.getLastName());
System.out.println(" Salary: "
+ employeeData.getSalary());
// As we have used Set to store data, during
// display
// also we need to use the set
// Iterate and get the skills one by one.
// An employee may have more than 1 skill
Set skillSets = employeeData.getSkillSets();
for (Iterator it = skillSets.iterator();
it.hasNext();) {
SkillsetData skillName
= (SkillsetData)it.next();
System.out.println(
"SkillName: "
+ skillName.getSkillName());
}
}
tx.commit();
}
// Catch block to handle exceptions
catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
}
// finally block which will execute for sure
finally {
// Closing all sessions
// using close() method
session.close();
}
}
Java
/* List down all the employees by using Hibernate criteria */
geekEmployeeObject.listGeekEmployeeData();
Java
// Java Program to illustrate Listing Employee Data
// Method
// Listing gfgEmployee Data
// Whose firstname like certain name
// and salary > certain value
// We can combine expressions using 'And','Or'
public void listGeekEmployeesByNameAndSalaryCriteria()
{
Session session = factory.openSession();
Transaction tx = null;
// Try block to check for exceptions
try {
tx = session.beginTransaction();
// This will simply return every object that
// corresponds to the GeekEmployee class.
Criteria geekEmployeeCriteria
= session.createCriteria(
GeekEmployeeData.class);
// Here 2 expectations are there one with salary and
// second one is name.
// Both are expected to be present. Let us see how
// to do that
Criterion salaryExpectation
= Restrictions.gt("salary", 50000);
Criterion nameExpectation
= Restrictions.ilike("firstName", "Geek%");
LogicalExpression logicalAndExpression
= Restrictions.and(salaryExpectation,
nameExpectation);
geekEmployeeCriteria.add(logicalAndExpression);
// As a list we can collect them and can iterate
List geekEmployeeList = geekEmployeeCriteria.list();
for (Iterator iterator
= geekEmployeeList.iterator();
iterator.hasNext();) {
GeekEmployeeData employeeData
= (GeekEmployeeData)iterator.next();
// Print statements
System.out.print("First Name: "
+ employeeData.getFirstName());
System.out.print(" Last Name: "
+ employeeData.getLastName());
System.out.println(" Salary: "
+ employeeData.getSalary());
Set skillSets = employeeData.getSkillSets();
for (Iterator it = skillSets.iterator();
it.hasNext();) {
SkillsetData skillName
= (SkillsetData)it.next();
// Print statement
System.out.println(
"SkillName: "
+ skillName.getSkillName());
}
}
tx.commit();
}
// Catch block to handle exceptions
catch (HibernateException e) {
if (tx != null)
tx.rollback();
// Display exception along with line number
// using printStacktrace() method
e.printStackTrace();
}
// finally block which will execute for sure
finally {
// Closing the connections
// to avoid memory leakage
session.close();
}
}
Java
// Let us add filter data by using Restrictions
geekEmployeeObject.listGeekEmployeesByNameAndSalaryCriteria();
现在让我们为“SkillsetData”表定义另一个 POJO 类。此类应具有 equals() 和 hashcode() 方法,并且绝对需要检查任何两个元素/对象是否相等
C. 技能组数据。Java
对于 SkillsetData 表数据 CRUD 操作,这是必需的
例子:
Java
public class SkillsetData {
private int id;
private String skillName;
public SkillsetData() {}
public SkillsetData(String skillName)
{
this.skillName = skillName;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getSkillName() { return skillName; }
public void setSkillName(String skillName)
{
this.skillName = skillName;
}
public boolean equals(Object obj)
{
// This method is definitely required in order to
// check whether any two elements/objects are equal
if (obj == null)
return false;
if (!this.getClass().equals(obj.getClass()))
return false;
SkillsetData obj2 = (SkillsetData)obj;
if ((this.id == obj2.getId())
&& (this.skillName.equals(
obj2.getSkillName()))) {
return true;
}
return false;
}
// collections calculate the hash value for a given key
// using the hashCode() method.
public int hashCode()
{
// This method is definitely required in order to
// check whether any two elements/objects are equal
int tmp = 0;
tmp = (id + skillName).hashCode();
return tmp;
}
}
D. 文件:休眠映射
由于我们有多对多关系,因此需要
- “name”属性设置为父类中定义的 Set 变量,在我们的例子中,我们必须引用“SkillsetData”。
- 对于每个“集合”变量,我们需要在映射文件中定义一个单独的集合元素。
- 这里我们使用“name”属性将中间表名设置为“ geekEmployeeSkill ”。
E.geekEmployeeData.hbm.xml
XML
This class contains the geekEmployeeData detail.
This class contains the skillset records.
mapping of the unique ID attribute in a class to the primary key of the corresponding database table. name attribute of the id element -> To the property in the class column attribute -> To the column in the database table. type attribute -> It holds the hibernate mapping type, This mapping types only will convert from Java to SQL data type. This is a very important one as this alone sets the relationship between “geekEmployeeData” and “SkillsetData”. “cascade” attribute has set to save-update-> Hibernate will persist the “SkillsetData” objects for SAVE i.e. CREATE and UPDATE operations at the same time as the “geekEmployeeData” objects. Concurrency should be obtained via this The “name” attribute is set to the defined Set variable in the parent class, here it represents “SkillsetData”. For each set variable, “name” attribute is to set the intermediate table name to “geekEmployeeSkill “. One “geekEmployeeData” object relates to many “SkillsetData” column attribute is used to link intermediate “geekEmployeeSkill”Root element Respective mappings from a Java class to a database table Optional one. Used for description Generates Primary key values automatically. mapping of a Java class property to its corresponding column in the database table. It represents a column in the “geekEmployeeSkill ” table. There we have foreign key to the parent object ie. table “geekEmployeeData” and links to the “skillId” in the “SkillsetData” table.
让我们看看我们需要指定MySQL连接的主要配置文件和参考hbm文件
F. 文件:hibernate.cfg.xml
XML
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/geeksforgeeks
root
xxxx
org.hibernate.dialect.MySQLDialect
true
true
update
G. 文件: GeekEmployeeManytoManyExample。Java
让我们用单独的方法分割文件。我们需要向表中添加一些记录,即“geekEmployeeData、SkillsetData 和 geekEmployeeSkill”表。通过使用 HashSet,我们可以将技能集一一添加,如下例所示:
例子:
Java
// Java Program to Illustrate GeekEmployeeManytoManyExample
// Class
// Importing required classes
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.Restrictions;
// Class
public class GeekEmployeeManytoManyExample {
// Class data member
private static SessionFactory factory;
// Main driver method
public static void main(String[] args)
{
// Try block to check for exceptions
try {
factory = new Configuration()
.configure()
.buildSessionFactory();
}
// Catch block to handle exceptions
catch (Throwable ex) {
// Display command when exception occurred
System.err.println(
"Failed to create sessionFactory object."
+ ex);
throw new ExceptionInInitializerError(ex);
}
GeekEmployeeManytoManyExample geekEmployeeObject
= new GeekEmployeeManytoManyExample();
// Let us have a set of skills for few employees
HashSet skillSets = new HashSet();
skillSets.add(new SkillsetData("Java"));
skillSets.add(new SkillsetData("Python"));
skillSets.add(new SkillsetData("R Programming"));
HashSet databaseSkillSets = new HashSet();
databaseSkillSets.add(new SkillsetData("MySQL"));
databaseSkillSets.add(
new SkillsetData("SQL Server"));
databaseSkillSets.add(new SkillsetData("MongoDB"));
HashSet generalSkillset = new HashSet();
generalSkillset.add(skillSets);
generalSkillset.add(databaseSkillSets);
// Add few employee records in database
Integer empID1 = geekEmployeeObject.addEmployee(
"GeekA", "GeekA", 100000, skillSets);
Integer empID2 = geekEmployeeObject.addEmployee(
"GeekB", "GeekB", 50000, databaseSkillSets);
Integer empID3 = geekEmployeeObject.addEmployee(
"GeekC", "GeekC", 50000, skillSets);
}
/* Method to CREATE an employee in the database. Inserts
data in
geekEmployeeData, SkillsetData and geekEmployeeSkill table
*/
public Integer addEmployee(String fname, String lname,
int salary, Set skillSets)
{
Session session = factory.openSession();
Transaction tx = null;
Integer employeeID = null;
try {
tx = session.beginTransaction();
GeekEmployeeData employee
= new GeekEmployeeData(fname, lname,
salary);
employee.setSkillSets(skillSets);
employeeID = (Integer)session.save(employee);
tx.commit();
}
catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
}
// finally block
finally {
// Closing the sessions
// using close() method
session.close();
}
return employeeID;
}
}
运行上述代码,我们可以在控制台中看到结果。
代码执行:
并行 检查表值:
让我们使用休眠条件查询列出记录。
使用“Set”存储数据,取回也需要使用“Set”来实现。由于我们使用休眠映射来拥有
例子:
Java
// Java Program to List the Records by
// Using Hibernate Criteria Query
// Method
public void listGeekEmployeeData()
{
Session session = factory.openSession();
Transaction tx = null;
// Try block to check for exceptions
try {
tx = session.beginTransaction();
Criteria geekEmployeeCriteria
= session.createCriteria(
GeekEmployeeData.class);
List geekEmployeeList = geekEmployeeCriteria.list();
for (Iterator iterator
= geekEmployeeList.iterator();
iterator.hasNext();) {
GeekEmployeeData employeeData
= (GeekEmployeeData)iterator.next();
System.out.print("First Name: "
+ employeeData.getFirstName());
System.out.print(" Last Name: "
+ employeeData.getLastName());
System.out.println(" Salary: "
+ employeeData.getSalary());
// As we have used Set to store data, during
// display
// also we need to use the set
// Iterate and get the skills one by one.
// An employee may have more than 1 skill
Set skillSets = employeeData.getSkillSets();
for (Iterator it = skillSets.iterator();
it.hasNext();) {
SkillsetData skillName
= (SkillsetData)it.next();
System.out.println(
"SkillName: "
+ skillName.getSkillName());
}
}
tx.commit();
}
// Catch block to handle exceptions
catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
}
// finally block which will execute for sure
finally {
// Closing all sessions
// using close() method
session.close();
}
}
Java
/* List down all the employees by using Hibernate criteria */
geekEmployeeObject.listGeekEmployeeData();
在列出员工数据的同时,我们甚至可以过滤掉具有多对多关系的数据。通过下面的代码,我们可以得到收入超过 50000 的 geekemployee 的详细信息以及他们的名字应该以 Geek 开头,其余的可以是任何东西。 “限制”正在习惯于实现这一目标。由于我们要添加 2 个条件,因此在其间设置了“And”。在这里,也可以通过使用“设置”,我们可以单独列出筛选出的员工的技能组合。
例子
Java
// Java Program to illustrate Listing Employee Data
// Method
// Listing gfgEmployee Data
// Whose firstname like certain name
// and salary > certain value
// We can combine expressions using 'And','Or'
public void listGeekEmployeesByNameAndSalaryCriteria()
{
Session session = factory.openSession();
Transaction tx = null;
// Try block to check for exceptions
try {
tx = session.beginTransaction();
// This will simply return every object that
// corresponds to the GeekEmployee class.
Criteria geekEmployeeCriteria
= session.createCriteria(
GeekEmployeeData.class);
// Here 2 expectations are there one with salary and
// second one is name.
// Both are expected to be present. Let us see how
// to do that
Criterion salaryExpectation
= Restrictions.gt("salary", 50000);
Criterion nameExpectation
= Restrictions.ilike("firstName", "Geek%");
LogicalExpression logicalAndExpression
= Restrictions.and(salaryExpectation,
nameExpectation);
geekEmployeeCriteria.add(logicalAndExpression);
// As a list we can collect them and can iterate
List geekEmployeeList = geekEmployeeCriteria.list();
for (Iterator iterator
= geekEmployeeList.iterator();
iterator.hasNext();) {
GeekEmployeeData employeeData
= (GeekEmployeeData)iterator.next();
// Print statements
System.out.print("First Name: "
+ employeeData.getFirstName());
System.out.print(" Last Name: "
+ employeeData.getLastName());
System.out.println(" Salary: "
+ employeeData.getSalary());
Set skillSets = employeeData.getSkillSets();
for (Iterator it = skillSets.iterator();
it.hasNext();) {
SkillsetData skillName
= (SkillsetData)it.next();
// Print statement
System.out.println(
"SkillName: "
+ skillName.getSkillName());
}
}
tx.commit();
}
// Catch block to handle exceptions
catch (HibernateException e) {
if (tx != null)
tx.rollback();
// Display exception along with line number
// using printStacktrace() method
e.printStackTrace();
}
// finally block which will execute for sure
finally {
// Closing the connections
// to avoid memory leakage
session.close();
}
}
Java
// Let us add filter data by using Restrictions
geekEmployeeObject.listGeekEmployeesByNameAndSalaryCriteria();
视频说明:
结论:编写复杂的查询,多个内连接使RDBMS中的数据检索。同样可以在休眠中以更简单和用户友好的方式实现。每当需要连接超过 1 个表时,就需要形成关系。 Hibernate 使关系变得更简单。