In RDBMS, we can see a very common usage of parent-child relationships. It can be achieved in Hibernate via
- One-to-many relationship
- Many-to-one relationship
- One-to-one relationship
- Many-to-many relationship
Here we will be discussing how to perform Hibernate – Many-to-Many mappings. Below are the example tables to demonstrate Many-to-Many mappings as listed below:
- geekEmployeeData
- SkillsetData
- geekEmployeeSkill
Implementation:
A. Steps for Table creation are as follows:
-- 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 table creation
A Many-to-Many mapping has to be implemented using a Set java collection and it should not contain any duplicate element. A Set can be mapped with a <set> element in the mapping table. It can be initialized with java.util.HashSet.
B. POJO classes
For geekEmployeeData table data CRUD operations, this is required
Example:
Java
import java.util.Set;
public class GeekEmployeeData {
private int id;
private String firstName;
private String lastName;
private int salary;
private Set skillSets;
public Set getSkillSets() { return skillSets; }
public void setSkillSets(Set skillSets)
{
this .skillSets = skillSets;
}
public GeekEmployeeData() {}
public GeekEmployeeData(String firstName,
String lastName, int salary)
{
this .firstName = firstName;
this .lastName = lastName;
this .salary = salary;
}
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;
}
}
|
Now let us define another POJO class for “SkillsetData” table. This class should have equals() and hashcode() method and is definitely required in order to check whether any two elements/objects are equal
C. SkillsetData.java
For SkillsetData table data CRUD operations, this is required
Example:
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)
{
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 ;
}
public int hashCode()
{
int tmp = 0 ;
tmp = (id + skillName).hashCode();
return tmp;
}
}
|
D. File: Hibernate-Mapping
As we are having many-to-many relationships, <set> element is required to define the rule.
The <set> element sets the relationship between two tables. Here it is between “GeekEmployeeData” and “SkillsetData” classes. We need to set “cascade attribute to save-update” to tell Hibernate to persist the “SkillsetData” objects for SAVE. i.e. “CREATE” and “UPDATE” operations should happen at the same time whenever there are changes in the “GeekEmployeeData” objects.
- The “name” attribute is set to the defined Set variable in the parent class, in our case, we have to refer “SkillsetData”.
- For each “set” variable, we need to define a separate set element in the mapping file.
- Here we used the “name” attribute to set the intermediate table name to “geekEmployeeSkill“.
E. geekEmployeeData.hbm.xml
XML
<? xml version = "1.0" encoding = "utf-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
< hibernate-mapping >
< class name = "com.geeksforgeeks.GeekEmployeeData" table = "geekEmployeeData" >
< meta attribute = "class-description" >
This class contains the geekEmployeeData detail.
</ meta >
< id name = "id" type = "int" column = "id" >
< generator class = "native" />
</ id >
< set name = "skillSets" cascade = "save-update" table = "geekEmployeeSkill" >
< key column = "geekEmpId" />
< many-to-many column = "skillId" class = "com.geeksforgeeks.SkillsetData" />
</ set >
< property name = "firstName" column = "first_name" type = "string" />
< property name = "lastName" column = "last_name" type = "string" />
< property name = "salary" column = "salary" type = "int" />
</ class >
< class name = "com.geeksforgeeks.SkillsetData" table = "SkillsetData" >
< meta attribute = "class-description" >
This class contains the skillset records.
</ meta >
< id name = "id" type = "int" column = "id" >
< generator class = "native" />
</ id >
< property name = "skillName" column = "skillName" type = "string" />
</ class >
</ hibernate-mapping >
|
<hibernate-mapping> |
Root element |
<class> |
Respective mappings from a Java class to a database table |
<meta> |
Optional one. Used for description |
<id> |
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.
|
<generator> of <id> |
Generates Primary key values automatically. |
<property> |
mapping of a Java class property to its corresponding column in the database table. |
<set> |
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 “.
|
<key> |
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. |
<many-to-many> |
One “geekEmployeeData” object relates to many “SkillsetData”
column attribute is used to link intermediate “geekEmployeeSkill”
|
Let us see the main configuration file where we need to specify MySQL connectivity and the reference hbm file
F. File: hibernate.cfg.xml
XML
<? xml version = "1.0" encoding = "utf-8" ?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
< hibernate-configuration >
< session-factory >
< property name = "hibernate.connection.driver_class" >com.mysql.jdbc.Driver</ property >
< property name = "hibernate.connection.username" >root</ property >
< property name = "hibernate.connection.password" >xxxx</ property >
< property name = "hibernate.dialect" >org.hibernate.dialect.MySQLDialect</ property >
< property name = "show_sql" >true</ property >
< property name = "format_sql" >true</ property >
< property name = "hbm2ddl.auto" >update </ property >
< mapping resource = "geekEmployeeData.hbm.xml" />
</ session-factory >
</ hibernate-configuration >
|
G. File: GeekEmployeeManytoManyExample.java
Let us split the file with individual methods. We need to add a few records to the table namely “geekEmployeeData, SkillsetData, and geekEmployeeSkill” table. By using HashSet, we can add the skillsets one by one as depicted in below example as follows:
Example:
Java
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;
public class GeekEmployeeManytoManyExample {
private static SessionFactory factory;
public static void main(String[] args)
{
try {
factory = new Configuration()
.configure()
.buildSessionFactory();
}
catch (Throwable ex) {
System.err.println(
"Failed to create sessionFactory object."
+ ex);
throw new ExceptionInInitializerError(ex);
}
GeekEmployeeManytoManyExample geekEmployeeObject
= new GeekEmployeeManytoManyExample();
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);
Integer empID1 = geekEmployeeObject.addEmployee(
"GeekA" , "GeekA" , 100000 , skillSets);
Integer empID2 = geekEmployeeObject.addEmployee(
"GeekB" , "GeekB" , 50000 , databaseSkillSets);
Integer empID3 = geekEmployeeObject.addEmployee(
"GeekC" , "GeekC" , 50000 , skillSets);
}
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 {
session.close();
}
return employeeID;
}
}
|
On running the above code, we can see the results in the console.
Code Execution:

Parallelly Checking the table values:


geekemployeeskill data
Let us list the records by using hibernate criteria query.
By using “Set”, data is stored, while retrieving also needs to use “Set” to achieve it. As we have used hibernate mapping to have <set>, it is easier to get the skillsets. Hibernate helps to achieve it easily. We no need to write complex inner join queries to achieve that. As we have set “show_sql” as true, in the console we can see the generated query. It is shown in the screenshot below.
Example:
Java
public void listGeekEmployeeData()
{
Session session = factory.openSession();
Transaction tx = null ;
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());
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 (HibernateException e) {
if (tx != null )
tx.rollback();
e.printStackTrace();
}
finally {
session.close();
}
}
|
Java
geekEmployeeObject.listGeekEmployeeData();
|

While listing out employee data, we can even filter out data as well for data which is having many-to-many relationships. Via the below code, we can get the details of geekemployee who is earning more than 50000 and their firstname that should start with Geek, and the rest can be anything. “Restrictions” are getting used to achieve that. As we are adding 2 conditions, it is set with “And” in between. Here also by using “Set” we can able to list out the skillsets of the filtered employee(s) alone.
Example
Java
public void listGeekEmployeesByNameAndSalaryCriteria()
{
Session session = factory.openSession();
Transaction tx = null ;
try {
tx = session.beginTransaction();
Criteria geekEmployeeCriteria
= session.createCriteria(
GeekEmployeeData. class );
Criterion salaryExpectation
= Restrictions.gt( "salary" , 50000 );
Criterion nameExpectation
= Restrictions.ilike( "firstName" , "Geek%" );
LogicalExpression logicalAndExpression
= Restrictions.and(salaryExpectation,
nameExpectation);
geekEmployeeCriteria.add(logicalAndExpression);
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());
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 (HibernateException e) {
if (tx != null )
tx.rollback();
e.printStackTrace();
}
finally {
session.close();
}
}
|
Java
geekEmployeeObject.listGeekEmployeesByNameAndSalaryCriteria();
|

Video explanation:
Conclusion: Writing complex queries, multiple inner joins make the retrieval of data in RDBMS. The same can be achieved in hibernate in an easier and user-friendly manner. Whenever there is a need of connecting more than 1 table, relationships need to be formed. Hibernate make the relationship easier way.
Whether you're preparing for your first job interview or aiming to upskill in this ever-evolving tech landscape,
GeeksforGeeks Courses are your key to success. We provide top-quality content at affordable prices, all geared towards accelerating your growth in a time-bound manner. Join the millions we've already empowered, and we're here to do the same for you. Don't miss out -
check it out now!
Last Updated :
05 Apr, 2022
Like Article
Save Article