📜  Hibernate – 多对多映射

📅  最后修改于: 2022-05-13 01:55:05.919000             🧑  作者: Mango

Hibernate – 多对多映射

在 RDBMS 中,我们可以看到非常常见的父子关系用法。它可以通过在 Hibernate 中实现

  1. 一对多关系
  2. 多对一关系
  3. 一对一的关系
  4. 多对多关系

在这里,我们将讨论如何执行 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)
);

geekEmployeeSkill 表创建

必须使用 Set Java集合来实现多对多映射,并且它不应包含任何重复元素。 Set 可以与映射表中的元素进行映射。它可以用Java.util.HashSet 初始化。

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. 文件:休眠映射

由于我们有多对多关系,因此需要元素来定义规则。

元素设置两个表之间的关系。这里它位于“ GeekEmployeeData ”和“ SkillsetData ”类之间。我们需要设置“ cascade 属性为 save-update ”来告诉 Hibernate 为 SAVE 持久化“SkillsetData”对象。即,只要“GeekEmployeeData”对象发生变化,“CREATE”和“UPDATE”操作就应该同时发生。

  • “name”属性设置为父类中定义的 Set 变量,在我们的例子中,我们必须引用“SkillsetData”。
  • 对于每个“集合”变量,我们需要在映射文件中定义一个单独的集合元素。
  • 这里我们使用“name”属性将中间表名设置为“ geekEmployeeSkill ”。

E.geekEmployeeData.hbm.xml

XML



 
  
  
  
      
      
         This class contains the geekEmployeeData detail.
      
      
      
         
      
       
      
      
         
         
           
       
      
      
      
       
   
    
   
       
      
         This class contains the skillset records.
      
       
      
         
      
       
      
       
   


Root element
Respective mappings from a Java class to a database table
Optional one. Used for description 

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.

of Generates Primary key values automatically.
mapping of a Java class property to its corresponding column in the database table.

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 “.

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.

One “geekEmployeeData” object relates to many “SkillsetData” 

column attribute is used to link intermediate “geekEmployeeSkill”

让我们看看我们需要指定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”来实现。由于我们使用休眠映射来拥有 ,因此更容易获得技能集。 Hibernate 有助于轻松实现它。我们不需要编写复杂的内部连接查询来实现这一点。由于我们已将“show_sql”设置为 true,因此在控制台中我们可以看到生成的查询。它显示在下面的屏幕截图中。

例子:

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 使关系变得更简单。