Hibernate Many to Many Example
Many-to-Many mapping is usually implemented in the database using a Join Table. For example, we can have Cart
and Item
tables and Cart_Items
table for many-to-many mapping. Every cart can have multiple items and every item can be part of multiple carts, so we have a many to many mapping here.
In this tutorial, we will learn about how to use Hibernate Many-To-Many Bidirectional mapping using annotation based configuration.
1. Introduction
Many-to-many mapping is an association between two entities where one instance of an entity is associated with the multiple instances of another entity and vice-versa. A many-to-many relationship always has two sides called an owning side and a non-owning side. The Join
operation of a table is defined on the owning side and the owning side has a field that stores collection of target entities.
The many-to-many association can be either unidirectional or bidirectional.
- In unidirectional association, only source entity has a relationship field that refers to the target entities. We can navigate this type of association from one side
- In bi-directional association, each entity (i.e. source and target) has a relationship field that refers to each other. We can navigate this type of association from both sides
But before we move on, let’s understand the Hibernate and the Annotations.
1.1 Hibernate
- Hibernate is an ORM (Object Relational Mapping) framework to communicate with the database using the Java API. This programming technique maps the object to the data stored in the database
- Provides data query and retrieval facilities and is purely used for data persistence (i.e. to store or retrieve data from the database)
- Framework internally uses the JDBC API to interact with the database and hides the internal JDBC implementations from end users
1.2 Hibernate Benefits
There are many advantages of using the Hibernate framework, for e.g.
- Takes care of mapping Java classes to database tables using XML or annotations and without writing any line of code
- Provides simple APIs for storing and retrieving Java objects directly to and from the database
- Provides the facility to create the tables of the database automatically and thereby reducing manual intervention
- If there is change in the database or in any table then we only need to change the XML properties or annotations
- Minimize database access with smart fetching strategies as Hibernate framework internally uses the cache technique
1.3 Hibernate Annotations
- Hibernate annotations is the newest way to define mappings without a use of an XML file
- Developers use annotations to provide metadata configuration along with the Java code. Thus, making the code easy to understand
- XML provides the ability to change the configuration without building the project. Thus, annotations are less powerful than XML configuration and should only be used for table and column mappings
- Annotations are preconfigured with sensible default values, which reduce the amount of coding required. For e.g. Class name defaults to Table name and field names defaults to column names
1.4 Reference Guide on Hibernate Annotations
Hibernate Annotations are based on the JPA 2 specification. All the JPA annotations are defined in the javax.persistence.*
package. The basic JPA annotations of Hibernate that can be used in an entity are the ones below.
Annotation | Modifier | Description |
@Entity | Marks a class as a Hibernate Entity (Mapped class) | |
@Table | Name | Maps this class with a database table specified by name modifier. If the name is not supplied it maps the class with a table having the same name as the class. |
@Id | Marks this class field as a primary key column. | |
@GeneratedValue | Instructs database to generate a value for this field automatically. | |
@Column | Name | Maps this field with table column specified by name and uses the field name if name modifier is absent. |
@ManyToMany | Cascade | Marks this field as the owning side of the many-to-many relationship and cascade modifier specifies which operations should cascade to the inverse side of the relationship. |
mappedBy | This modifier holds the field which specifies the inverse side of the relationship. | |
@JoinTable | Name | For holding this many-to-many relationship, maps this field with an intermediary database join table specified by name modifier. |
joinColumns | Identifies the owning side of columns which are necessary to identify a unique owning object. | |
inverseJoinColumns | Identifies the inverse (target) side of columns which are necessary to identify a unique target object. | |
@JoinColumn | Name | Maps a join column specified by the name identifier to the relationship table specified by @JoinTable . |
1.5 Download and Install Hibernate
You can read this tutorial in order to download and install Hibernate in the Eclipse IDE.
1.6 Download and Install MySQL
You can watch this video in order to download and install the MySQL database on your Windows operating system.
Now, open up the Eclipse IDE and let’s see how to implement Many-to-Many relationship in Hibernate using Annotation!
2. Hibernate Many to Many Example
2.1 Tools Used
We are using Eclipse Kepler SR2, JDK 7, MySQL database and Maven. Having said that, we have tested the code against JDK 1.8 and it works well.
2.2 Project Structure
Firstly, let’s review the final project structure, in case you are confused about where you should create the corresponding files or folder later!
2.3 Project Creation
This section will demonstrate on how to create a Java based Maven project with Eclipse. In Eclipse IDE, go to File -> New -> Maven Project
.
In the New Maven Project window, it will ask you to select project location. By default, ‘Use default workspace location‘ will be selected. Select the ‘Create a simple project (skip archetype selection)‘ checkbox and just click on next button to proceed.
It will ask you to ‘Enter a group id for the artifact.’ We will input the details as shown in the below image. The version number will be by default 0.0.1-SNAPSHOT
.
Click on Finish and the creation of the a maven project is completed. If you observe, it has downloaded the maven dependencies and a pom.xml
file will be created. It will have the following code:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>HibernateManyToManyMapping</groupId> <artifactId>HibernateManyToManyMapping</artifactId> <version>0.0.1-SNAPSHOT</version> </project>
We can start adding the dependencies that developers want like Hibernate, MySQL etc. Let’s start building the application!
3. Application Building
Below are the steps involved in developing this application.
3.1 Database & Table Creation
The following MySQL script is used to create a database called tutorialDb
with three tables: employee
, meeting
and employee_meeting
(Join Table). Open MySQL terminal or workbench terminal and execute the script:
CREATE DATABASE tutorialDb; USE tutorialDb; CREATE TABLE employee ( employee_id int(10) NOT NULL AUTO_INCREMENT, firstname VARCHAR(50) NULL DEFAULT NULL, lastname VARCHAR(50) NULL DEFAULT NULL, PRIMARY KEY (employee_id) ); CREATE TABLE meeting ( meeting_id int(20) NOT NULL AUTO_INCREMENT, subject VARCHAR(50) NOT NULL, meeting_date DATE NOT NULL, PRIMARY KEY (meeting_id) ); CREATE TABLE employee_meeting ( employee_id int(20) NOT NULL, meeting_id int(20) NOT NULL, PRIMARY KEY (employee_id, meeting_id), INDEX FK_MEETING (meeting_id), CONSTRAINT FK_EMPLOYEE FOREIGN KEY (employee_id) REFERENCES employee (employee_id), CONSTRAINT FK_MEETING FOREIGN KEY (meeting_id) REFERENCES meeting (meeting_id) );
If everything goes well, the table will be shown in the MySQL workbench. Below diagram shows the Entity relationship between these tables.
3.2 Maven Dependencies
Here, we specify only two dependencies for Hibernate Core and MySQL Connector. Rest dependencies will be auto resolved by Maven, such as Hibernate JPA and Hibernate Commons Annotations. The updated file will have the following code:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>HibernateManyToManyMapping</groupId> <artifactId>HibernateManyToManyMapping</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <!-- Hibernate 4.3.6 Final --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.3.6.Final</version> </dependency> <!-- Mysql Connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.21</version> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> </build> </project>
3.3 Java Class Creation
Let’s create the required Java files. Right click on src/main/java
folder, New -> Package
.
A new pop window will open where we will enter the package name as: com.jcg.hibernate.many2many.mapping
.
Once the package is created in the application, we will need to create the model and implementation classes. Right click on the newly created package: New -> Class
.
A new pop window will open and enter the file name as Employee
. The owner entity class will be created inside the package: com.jcg.hibernate.many2many.mapping
.
Repeat the step (i.e. Fig. 9) and enter the filename as Meeting
. The mapped entity class will be created inside the package: com.jcg.hibernate.many2many.mapping
.
Again, repeat the step listed in Fig. 9 and enter the file name as AppMain
. The implementation class will be created inside the package: com.jcg.hibernate.many2many.mapping
.
3.3.1 Implementation of Owner Entity
Owner entity is the entity which is responsible for making the association and maintaining it. In our case, I am making Employee
as the owner entity. @JoinTable
annotation has been used to make this association. Add the following code to it:
Employee.java
package com.jcg.hibernate.many2many.mapping; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; @Entity @Table(name="employee") public class Employee { @Id @Column(name="employee_id") @GeneratedValue private Long employeeId; @Column(name="firstname") private String firstname; @Column(name="lastname") private String lastname; @ManyToMany(cascade = {CascadeType.ALL}) @JoinTable(name="employee_meeting", joinColumns= {@JoinColumn(name="employee_id")}, inverseJoinColumns= {@JoinColumn(name="meeting_id")}) private Set meetings = new HashSet(); public Employee() { } public Employee(String first_name, String last_name) { this.firstname = first_name; this.lastname = last_name; } public Long getEmployeeId() { return employeeId; } public void setEmployeeId(Long employee_id) { this.employeeId = employee_id; } public String getFirstname() { return firstname; } public void setFirstname(String first_name) { this.firstname = first_name; } public String getLastname() { return lastname; } public void setLastname(String last_name) { this.lastname = last_name; } public Set getMeetings() { return meetings; } public void setMeetings(Set meetings) { this.meetings = meetings; } }
3.3.2 Implementation of Mapped Entity
Our mapped entity is Meeting
which is mapped to Employee
using mappedBy
attribute. Add the following code to it:
Meeting.java
package com.jcg.hibernate.many2many.mapping; import java.util.Date; import java.util.HashSet; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToMany; import javax.persistence.Table; @Entity @Table(name="meeting") public class Meeting { @Id @Column(name="meeting_id") @GeneratedValue private Long meetingId; @Column(name="subject") private String subject; @Column(name="meeting_date") private Date meetingDate; @ManyToMany(mappedBy="meetings") private Set employees = new HashSet(); public Meeting() { } public Meeting(String subject) { this.subject = subject; this.meetingDate = new Date(); } public Long getMeetingId() { return meetingId; } public void setMeetingId(Long meeting_id) { this.meetingId = meeting_id; } public String getSubject() { return subject; } public void setSubject(String subject_name) { this.subject = subject_name; } public Date getMeetingDate() { return meetingDate; } public void setMeetingDate(Date meeting_date) { this.meetingDate = meeting_date; } public Set getEmployees() { return employees; } public void setEmployees(Set employees) { this.employees = employees; } }
3.3.3 Implementation of Utility Class
This class helps in creating the SessionFactory
from the Hibernate configuration file and interacts with the database to perform the INSERT
operation. Add the following code to it:
AppMain.java
package com.jcg.hibernate.many2many.mapping; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; public class AppMain { static Session sessionObj; static SessionFactory sessionFactoryObj; private static SessionFactory buildSessionFactory() { // Creating Configuration Instance & Passing Hibernate Configuration File Configuration configObj = new Configuration(); configObj.configure("hibernate.cfg.xml"); // Since Hibernate Version 4.x, ServiceRegistry Is Being Used ServiceRegistry serviceRegistryObj = new StandardServiceRegistryBuilder().applySettings(configObj.getProperties()).build(); // Creating Hibernate SessionFactory Instance sessionFactoryObj = configObj.buildSessionFactory(serviceRegistryObj); return sessionFactoryObj; } public static void main(String[] args) { try { sessionObj = buildSessionFactory().openSession(); sessionObj.beginTransaction(); Meeting quaterlyMeet = new Meeting("Quaterly Status Meeting"); Meeting weeklyMeet = new Meeting("Weekly Status Meeting"); Meeting dailyMeet = new Meeting("Daily Status Meeting"); Employee empObj1 = new Employee("Happy", "Potter"); empObj1.getMeetings().add(quaterlyMeet); empObj1.getMeetings().add(weeklyMeet); sessionObj.save(empObj1); Employee empObj2 = new Employee("Lucifer", "Morningstar"); empObj2.getMeetings().add(quaterlyMeet); sessionObj.save(empObj2); Employee empObj3 = new Employee("April O'", "Neil"); empObj3.getMeetings().add(weeklyMeet); empObj3.getMeetings().add(dailyMeet); sessionObj.save(empObj3); // Committing The Transactions To The Database sessionObj.getTransaction().commit(); System.out.println("\n.......Records Saved Successfully To The Database......."); } catch(Exception sqlException) { if(null != sessionObj.getTransaction()) { System.out.println("\n.......Transaction Is Being Rolled Back......."); sessionObj.getTransaction().rollback(); } sqlException.printStackTrace(); } finally { if(sessionObj != null) { sessionObj.close(); } } } }
3.4. Hibernate Configuration File
To configure the Hibernate framework, we need to implement a configuration file i.e. hiberncate.cfg.xml
. Right click on src/main/resources
folder, New -> Other
.
A new pop window will open and select the wizard as XML file.
Again, a pop-up window will open. Verify the parent folder location as HibernateManyToManyMapping/src/main/resources
and enter the file name as hibernate.cfg.xml
. Click Finish.
Once the file is created, we will include the database configuration. Add the following code to it:
hibernate.cfg.xml
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- SQL Dialect --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- Database Connection Settings --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/tutorialDb</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password"></property> <property name="show_sql">true</property> <!-- Specifying Session Context --> <property name="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</property> <!-- Mapping With Model Class Containing Annotations --> <mapping class="com.jcg.hibernate.many2many.mapping.Employee" /> <mapping class="com.jcg.hibernate.many2many.mapping.Meeting" /> </session-factory> </hibernate-configuration>
Notes:
- Here, we instructed Hibernate to connect to a MySQL database named
tutorialDb
and the Mapping classes to be loaded - We have also instructed Hibernate framework to use
MySQLDialect
i.e. Hibernate will optimize the generated SQL statements for MySQL - This configuration will be used to create a Hibernate
SessionFactory
object
4. Run the Application
To run the Hibernate application, Right click on the AppMain
class, Run As -> Java Application
.
5. Project Demo
On executing the AppMain
class, you will see the records in employee
, meeting
, and employee_meeting
tables. Developers can debug the example and see what happens in the database after every step. Enjoy!
Below is the snapshot of MySQL Database after execution of the above program.
Employee Table
Meeting Table
Employee Meeting Table
That’s all for this post. Happy Learning!!
6. Conclusion
In Many-To-Many association, an extra table is used (known as Joined table) whose primary key is the combination of the primary key of both the associated tables. In other words, there is a foreign key association between the joined table and the associated tables. That’s all for Hibernate Many-To-Many mapping example tutorial and I hope this article served you whatever you were looking for.
7. Download the Eclipse Project
This was an example of Hibernate Many-To-Many Mapping.
You can download the full source code of this example here: Hibernate Many2Many Mapping Example