Hibernate – Many-to-Many example (XML Mapping)
Many-to-many relationships occur when each record in an entity may have many linked records in another entity and vice-versa.
In this tutorial, we show you how to work with many-to-many table relationship in Hibernate, via XML mapping file (hbm).
For many to many with extra columns in join table, please refer to this tutorial.
Tools and technologies used in this tutorials :
- Hibernate 3.6.3.Final
- MySQL 5.1.15
- Maven 3.0.3
- Eclipse 3.6
Project Structure
Project structure of this tutorial.

Project Dependency
Get latest hibernate.jar from JBoss repository.
File : pom.xml
<project ...> <repositories> <repository> <id>JBoss repository</id> <url>http://repository.jboss.org/nexus/content/groups/public/</url> </repository> </repositories> <dependencies> <!-- MySQL database driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.15</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>3.6.3.Final</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> </dependencies> </project>
1. “Many-to-many” example
This is a many-to-many relationship table design, a STOCK table has more than one CATEGORY, and CATEGORY can belong to more than one STOCK, the relationship is linked with a third table called STOCK_CATEGORY.
Table STOCK_CATEGORY only consist of two primary keys, and also foreign key reference back to STOCK and CATEGORY.

MySQL table scripts
CREATE TABLE `stock` ( `STOCK_ID` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `STOCK_CODE` VARCHAR(10) NOT NULL, `STOCK_NAME` VARCHAR(20) NOT NULL, PRIMARY KEY (`STOCK_ID`) USING BTREE, UNIQUE KEY `UNI_STOCK_NAME` (`STOCK_NAME`), UNIQUE KEY `UNI_STOCK_ID` (`STOCK_CODE`) USING BTREE ) CREATE TABLE `category` ( `CATEGORY_ID` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `NAME` VARCHAR(10) NOT NULL, `DESC` VARCHAR(255) NOT NULL, PRIMARY KEY (`CATEGORY_ID`) USING BTREE ) CREATE TABLE `stock_category` ( `STOCK_ID` INT(10) UNSIGNED NOT NULL, `CATEGORY_ID` INT(10) UNSIGNED NOT NULL, PRIMARY KEY (`STOCK_ID`,`CATEGORY_ID`), CONSTRAINT `FK_CATEGORY_ID` FOREIGN KEY (`CATEGORY_ID`) REFERENCES `category` (`CATEGORY_ID`), CONSTRAINT `FK_STOCK_ID` FOREIGN KEY (`STOCK_ID`) REFERENCES `stock` (`STOCK_ID`) )
2. Hibernate Model Class
Create two model classes – Stock.java and Category.java, to represent the above tables. No need to create an extra class for table ‘stock_category‘.
File : Stock.java
package com.mkyong.stock; import java.util.HashSet; import java.util.Set; public class Stock implements java.io.Serializable { private Integer stockId; private String stockCode; private String stockName; private Set<Category> categories = new HashSet<Category>(0); //getter, setter and constructor }
File : Category.java
package com.mkyong.stock; import java.util.HashSet; import java.util.Set; public class Category implements java.io.Serializable { private Integer categoryId; private String name; private String desc; private Set<Stock> stocks = new HashSet<Stock>(0); //getter, setter and constructor }
3. Hibernate XML Mapping
Now, create two Hibernate mapping files (hbm) – Stock.hbm.xml and Category.hbm.xml. You will noticed the third ‘stock_category‘ table is reference via “many-to-many” tag.
File : Stock.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.mkyong.stock.Stock" table="stock" catalog="mkyongdb"> <id name="stockId" type="java.lang.Integer"> <column name="STOCK_ID" /> <generator class="identity" /> </id> <property name="stockCode" type="string"> <column name="STOCK_CODE" length="10" not-null="true" unique="true" /> </property> <property name="stockName" type="string"> <column name="STOCK_NAME" length="20" not-null="true" unique="true" /> </property> <set name="categories" table="stock_category" inverse="false" lazy="true" fetch="select" cascade="all" > <key> <column name="STOCK_ID" not-null="true" /> </key> <many-to-many entity-name="com.mkyong.stock.Category"> <column name="CATEGORY_ID" not-null="true" /> </many-to-many> </set> </class> </hibernate-mapping>
File : Category.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.mkyong.stock.Category" table="category" catalog="mkyongdb"> <id name="categoryId" type="java.lang.Integer"> <column name="CATEGORY_ID" /> <generator class="identity" /> </id> <property name="name" type="string"> <column name="NAME" length="10" not-null="true" /> </property> <property name="desc" type="string"> <column name="[DESC]" not-null="true" /> </property> <set name="stocks" table="stock_category" inverse="true" lazy="true" fetch="select"> <key> <column name="CATEGORY_ID" not-null="true" /> </key> <many-to-many entity-name="com.mkyong.stock.Stock"> <column name="STOCK_ID" not-null="true" /> </many-to-many> </set> </class> </hibernate-mapping>
4. Hibernate Configuration File
Now, puts Stock.hbm.xml and Category.hbm.xml and MySQL detail in hibernate.cfg.xml.
File : 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> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mkyongdb</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">password</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="show_sql">true</property> <property name="format_sql">true</property> <mapping resource="com/mkyong/stock/Stock.hbm.xml" /> <mapping resource="com/mkyong/stock/Category.hbm.xml" /> </session-factory> </hibernate-configuration>
5. Run It
Run it, Hibernate will insert a record into the STOCK table, two records into the CATEGORY table, and also two records into the STOCK)CATEGORY table.
File : App.java
package com.mkyong; import java.util.HashSet; import java.util.Set; import org.hibernate.Session; import com.mkyong.stock.Category; import com.mkyong.stock.Stock; import com.mkyong.util.HibernateUtil; public class App { public static void main(String[] args) { System.out.println("Hibernate many to many (XML Mapping)"); Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Stock stock = new Stock(); stock.setStockCode("7052"); stock.setStockName("PADINI"); Category category1 = new Category("CONSUMER", "CONSUMER COMPANY"); Category category2 = new Category("INVESTMENT", "INVESTMENT COMPANY"); Set<Category> categories = new HashSet<Category>(); categories.add(category1); categories.add(category2); stock.setCategories(categories); session.save(stock); session.getTransaction().commit(); System.out.println("Done"); } }
Output …result should be self-explanatory
Hibernate many TO many (XML Mapping) Hibernate: INSERT INTO mkyongdb.stock (STOCK_CODE, STOCK_NAME) VALUES (?, ?) Hibernate: INSERT INTO mkyongdb.category (NAME, `DESC`) VALUES (?, ?) Hibernate: INSERT INTO mkyongdb.category (NAME, `DESC`) VALUES (?, ?) Hibernate: INSERT INTO stock_category (STOCK_ID, CATEGORY_ID) VALUES (?, ?) Hibernate: INSERT INTO stock_category (STOCK_ID, CATEGORY_ID) VALUES (?, ?) Done
For many-to-many in Hibernate annotation, please refer to this example.
hey hi all harsha here
i do hv small problem with hibernate, its related to the topic under discussion.
could u please tell me
in Stocks , category , Stock_Category tables
for me category remains constant, i don’t wanna change it (means i do have constant category table)
so if i create new stocks and add existing categories to it what to do
if i try the above its quite works but Category table is unnecessarily getting updated even tho new category is not getting inserted……
i don’t wan any changes to be made on category table.
help me with this
means i need little bit of help in hibernate mapping file
The faster way is use Hibernate tools to generate your mapping file automatically. Refer to following two articles.
http://www.mkyong.com/hibernate/how-to-install-hibernate-tools-in-eclipse-ide/
http://www.mkyong.com/hibernate/how-to-generate-code-with-hibernate-tools/
Can you please explain the mapping what it means , like
what does this means , what is what it refers to ,
[...] Author: mkyong In this tutorial, it will reuse the entire infrastructure of the previous “Hibernate many to many relationship example – XML mapping” tutorial, enhance it to support [...]
the project download is missing a lot of dependent jar files.
Maven-based project, use maven to download it.
MYkong, I love your website. But in this example I’m thinking you simply did something just for the sake of providing an example.
IT does not seem practical to have Category store Set where each StockCategory has the (parent) Category repeating in it. Not withstanding the fact that M-M relationship can be broken into 1-M and M-1 relationship, even practically that would seem to be the intent. Stock needs to know all its Categories and Category needs to know all Stocks in it.
Finally, and this may be Hibernate thingy, I refuse to accept understand the logic behind making a Class to represent a “Link Table” for the M-M relationship. My domain classes are Stock and Category. They mirror analysis of my Business and correspond to STOCK and CATEGORY Entities aka “Tables in RDBMS”. The “link table” is NOT a Business Entity and having a class to represent it just plain bad design.
Just my two cents.
This example is not something for the sake of providing example. The link table is a common RDBMS table design pattern for M-M relationship.
For hibernate, there are many ways to implement M-M table design, and the link table class is just one of the way, i will provide more ways in coming future.
I understand this might be Hibernate specific way. But that’s precisely my problem. You make a tongue in cheek remark in your essay on how you convinced your management to use Hibernate. You cite there is lot of demand for Hibernate as one of the reasons
My problem is my Domain and Architectural decisions should not be held hostage to tool I’m using for data persistence. Creating a domain class for representing a link table IMHO is not good design because the Link Class has no parallel representation in my Business Domain. The Link Class is simply adulterating my Java Domain.
I will look forward to your example of an alternative which does not make it necessary to create a Link Class.
Dear All ,
I have just gone through one site, and found the explantion with simple example of Many to Many relation in hibernate using JPA .
http://j2eereference.com/2011/01/many-to-many-mapping-in-hibernate/
I am taking up the subject java programming SE. I will try this and maybe if I don’t understand some of the codes, I can ask my professor about it.
if I have an attribute in the table StockCategory date???
Actually M-M relationship can be decomposed in to two 1-M relationships, but I do not need this extra effort unless I’ve extra columns in the mapper table that I really need(e.g. date of stock_category).
In M-M , read operations work fine, but save/delete/update is not quite easy!
Normally, a many to many relationship is realized by using the @ManyToMany annotation. So let’s say you have users and roles and each user can have a number of roles, while a certain role can belong to a number of users. Then you would use something like this:
Class User {
…
@ManyToMany(targetEntity = Role.class)
@JoinTable(name = “user_has_role”,
joinColumns = @JoinColumn(name = “userId”),
inverseJoinColumns = @JoinColumn(name = “roleId”)
)
public Set getRoles() {
return roles;
}
…
}
Of course you need a third table to map this kind of relationship, but I dont’t understand why you are using the @ManyToOne annotation.
As i know, there are many ways to implement the many to many relationship, all lead to Rome.
Btw, thanks for sharing your thought.
[...] Many-to-many relationship example A many-to-many relationship project demonstration. [...]
Thanks for this tutorial,
I am wondering, if it possible, if in this case STOCK_CATEGORY table will be having composite primary key with
CATEGORY_ID and STOCK_ID i.e. no other PK in this case.
Then How will we define many to many relationship.
I am struggling to resolve this scenario.
hi,
Found the tutorial quite useful. Thanks
please can you also post hibernate many-many CRUD application? For example, Instead of adding a new category, I want to reference existing category in my Stock class, all I need to do is to insert Stock table and into the mapping table.
can you help pls?
You are completely wrong regarding mapping of many-to-many. I dont see anything like many-to-many. You are just trying to give alternate way but not exact code or tutorial. Please verify it since it is misleading the developer….
Thanks
sunil
oh.. you can download the full sample at the end of the article, both in xml mapping and annotation ways.
Would you mind to tell me which “way” or “word” i misleading the developer? and what wrong with this tutorial? In database, many to many is always involve third table for the relationship. Look forward your idea and comment.
Dear mkyong,
You are absolutly right .We need a third table to connect the two tables which we need to establish the relation. This is the way to implement the Many to Many relation using hibernate and JPA.
Actually speaking, third table doesnt need a primary key and we dont need to create a clas for the table stockCategory and ManyTone is not really required.
please go throught this article .
http://j2eereference.com/2011/01/many-to-many-mapping-in-hibernate/
Regards,
Rakesh.B.K
Hi Rakesh, thanks for your inputs.
For large table , primary key is a must
, class for “stockCategory” is just another way to achieve the same thing.
Hi mkyong, I was just commented on the example you gave. Anyways nice good article.