Investigating Hibernate Associations – Many to Many

In my previous posts, we have looked at one-to-one and one-to-many hibernate associations. This one is going to focus on many-to-many hibernate association.

Let’s start with an unidirectional many-to-many association and later move on to bi-directional association. We will continue to use the earlier examples of Person and Phone. Here’s the hibernate.cfg.xml file used for this example:



        <!-- Database connection settings -->
        <property name="connection.driver_class">
        <property name="connection.url">
        <property name="connection.username"><dbuser></property>
        <property name="connection.password"><dbpassword></property>

	<property name="transaction.factory_class">

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="">update</property>
        <property name="hibernate.max_fetch_depth">1</property>

        <mapping resource="com/tutorial/hibernate/simple/Person.hbm.xml"/>
        <mapping resource="com/tutorial/hibernate/simple/Phone.hbm.xml"/>




CREATE TABLE person (ID     varchar(255) NOT NULL,
                     FIRSTNAME     varchar(255),
                     LASTNAME      varchar(255),
                     DOB           date);
CREATE TABLE phone (ID      varchar(255) NOT NULL,
                    CONTACTNUMBER     varchar(10),
                    PHONETYPE         varchar(255));
CREATE TABLE person_phone (PERSONID     varchar(255),
                           PHONEID      varchar(255));

The hibernate configuration files for Person and Phone classes are as follows:

For Person

<hibernate-mapping package="com.tutorial.hibernate.simple">

    <class name="Person" table="PERSON" dynamic-update="true"
	dynamic-insert="true" select-before-update="false">
        <id name="id">
            <generator class="assigned"/>
        <property name="firstName"/>
        <property name="lastName"/>
        <property name="dob" type="date" />

	<set name="phones" table="PERSON_PHONE" cascade="all">
		<key column="PERSONID"/>
		<many-to-many column="PHONEID" class="Phone"/>



For Phone:

<hibernate-mapping package="com.tutorial.hibernate.simple">

    <class name="Phone" table="PHONE" dynamic-update="true"
	dynamic-insert="true" select-before-update="false">
        <id name="id">
            <generator class="assigned"/>
        <property name="number" column="contactnumber"/>
        <property name="type" column="phonetype"/>


The Person class will have the following attributes id, firstName, lastName, dob with their getters and setters. Add the following attribute and appropriate getters and setters for the phone collection.

private Set phones = new HashSet();

public Set getPhones() {
	return phones;

public void setPhones(Set phones) {
	this.phones = phones;

public void addPhone(Phone phone) {

The Phone class will have the following attributes id, number, type and their getters and setters.

Here's the sample test program for many to many relationship.

	Configuration cfg = new Configuration();
	SessionFactory sessFactory = cfg.buildSessionFactory();
	try {
		Session session = sessFactory.openSession();

		Person p1 = new Person();
		p1.setDob(new java.util.Date());

		Person p2 = new Person();
		p2.setDob(new java.util.Date());

		Phone phone1 = new Phone();

		Phone phone2 = new Phone();

		Transaction tx = session.beginTransaction();;;

	} catch(Exception e) {

The many-to-many relationship definition in Person.hbm.xml, the set attribute is defined as follows:

<set name="phones" table="PERSON_PHONE" cascade="all">
	<key column="PERSONID"/>
	<many-to-many column="PHONEID" class="Phone"/>

The cascade=”all” ensures that the INSERT order is appropriate. I.e. the insertion order is in the following fashion PERSON, PHONE and PERSON_PHONE.

Here’s the SQL output generated:

Hibernate: select, phone_.contactnumber as contactn2_2_,
	   phone_.phonetype as phonetype2_ from PHONE phone_
Hibernate: select, phone_.contactnumber as contactn2_2_,
	   phone_.phonetype as phonetype2_ from PHONE phone_
Hibernate: insert into PERSON (firstName, lastName, dob, id)
	   values (?, ?, ?, ?)
Hibernate: insert into PHONE (contactnumber, phonetype, id)
	   values (?, ?, ?)
Hibernate: insert into PHONE (contactnumber, phonetype, id)
	   values (?, ?, ?)
Hibernate: insert into PERSON (firstName, lastName, dob, id)
	   values (?, ?, ?, ?)
Hibernate: insert into PERSON_PHONE (PERSONID, PHONEID) values (?, ?)
Hibernate: insert into PERSON_PHONE (PERSONID, PHONEID) values (?, ?)
Hibernate: insert into PERSON_PHONE (PERSONID, PHONEID) values (?, ?)
Hibernate: insert into PERSON_PHONE (PERSONID, PHONEID) values (?, ?)

Here’s how the data is inserted in the tables:


-----   --------- -------- -------
1245	Clark	  Kent	   2007-09-25
12456	Bruce	  Willis   2007-09-25


----    ------------- ---------
451	1234567	      BUS
452	7654321	      PER


-------- -------
1245	 452
1245	 451
12456	 452
12456	 451

Moving on, let’s get a bi-directional many-to-many association going. Add the following in the Phone.hbm.xml

<set name="persons" inverse="true" table="PERSON_PHONE">
       	<key column="PHONEID"/>
       	<many-to-many column="PERSONID"

Add the following code in the Phone class:

private Set persons = new HashSet();

public Set getPersons() {
	return persons;

public void setPersons(Set persons) {
	this.persons = persons;

Add the following test code in our sample code after the tx.commit() line.

        Transaction tx1 = session.beginTransaction();
	Person per = (Person)session.load(Person.class, "12456");

Now we have bi-directional relationship working. the attribute definition inverse=”true” informs Hibernate that Person class is responsible for maintaining the relationship.

In my next post I intend do a deep dive in understanding the cascade attribute. Until the next post.

Categories: Hibernate | 40 Comments

Post navigation

40 thoughts on “Investigating Hibernate Associations – Many to Many

  1. Pingback: Investigating Hibernate Associations - Cascading Styles « My experiments with technology - My oasis in the desert of Project Management

  2. josue


    Try to follow your example but my primary key is a sequence and I hope I can help thanks.

    CREATE TABLE “telefonoCliente_cliente”
    clave_cliente numeric(20),
    clave_telefono_cliente numeric(20),
    CONSTRAINT “telefonoCliente_cliente_cve_cliente_fkey” FOREIGN KEY (clave_cliente)
    REFERENCES cliente (clave_cliente) MATCH SIMPLE
    CONSTRAINT “telefonoCliente_cliente_cve_tel_fkey” FOREIGN KEY (clave_telefono_cliente)
    REFERENCES telefono_cliente (clave_telefono_cliente) MATCH SIMPLE

    CREATE TABLE cliente
    clave_cliente numeric(20) NOT NULL,
    nombre_cliente character varying(40) NOT NULL,
    apellidos_cliente character varying(60) NOT NULL,
    direccion_cliente character varying(200) NOT NULL,
    identificador_cliente character varying(20) NOT NULL,
    tipo_cliente character varying(25) NOT NULL,
    CONSTRAINT cliente_pkey PRIMARY KEY (clave_cliente),
    CONSTRAINT cliente_tipo_cliente_check CHECK (tipo_cliente::text = ANY (ARRAY[‘PUBLICO GENERAL’::character varying, ‘CLIENTE ESPECIAL’::character varying]::text[]))

    CREATE TABLE telefono_cliente
    clave_telefono_cliente numeric(20) NOT NULL,
    telefono_cliente character varying(30) NOT NULL,
    CONSTRAINT telefono_cliente_pkey PRIMARY KEY (clave_telefono_cliente)



    package hibernate;

    import java.util.HashSet;
    import java.util.Set;

    * @author isaac
    public class Cliente {

    private Integer claveCliente;
    private String nombreCliente;
    private String apellidosCliente;
    private String direccionCliente;
    private String identificadorCliente;
    private String tipoCliente;

    private Set telefonosClientes = new HashSet();

    public Set getTelefonosClientes() {
    return telefonosClientes;

    public void setTelefonosClientes(Set phones) {
    this.telefonosClientes = phones;

    public void addtelefonosClientes(TelefonoCliente phone) {

    /*private Set telefonosClientes;

    public Set getTelefonosClientes() {
    return telefonosClientes;

    public void setTelefonosClientes(Set telCliente) {
    this.telefonosClientes = telCliente;

    public Integer getClaveCliente() {
    return claveCliente;

    public void setClaveCliente(Integer cve) {
    claveCliente = cve;

    public String getNombreCliente() {
    return nombreCliente;

    public void setNombreCliente(String string) {
    nombreCliente = string;

    public String getApellidosCliente() {
    return apellidosCliente;

    public void setApellidosCliente(String string) {
    apellidosCliente = string;

    public String getDireccionCliente() {
    return direccionCliente;

    public void setDireccionCliente(String string) {
    direccionCliente = string;

    public String getIdentificadorCliente() {
    return identificadorCliente;

    public void setIdentificadorCliente(String string) {
    identificadorCliente = string;

    public String getTipoCliente() {
    return tipoCliente;

    public void setTipoCliente(String string) {
    tipoCliente = string;


    package hibernate;

    import java.util.HashSet;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;

    * @author Deepak Kumar
    * Hibernate example to inset data into Contact table
    public class FirstExample {
    public static void main(String[] args) {
    Session session = null;

    // This step will read hibernate.cfg.xml and prepare hibernate for use
    SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
    session =sessionFactory.openSession();

    //Create new instance of Contact and set values in it by reading them from form object

    Cliente cliente = new Cliente();

    TelefonoCliente telefonoCliente = new TelefonoCliente();

    cliente.setNombreCliente(“isaac pedro”);
    cliente.setApellidosCliente(“legorreta perez”);
    cliente.setTipoCliente(“PUBLICO GENERAL”);
    cliente.setDireccionCliente(“Lago Sayula 101 col seminario”);



    Transaction tx = session.beginTransaction();;


    }catch(Exception e){
    // Actual contact insertion will happen at this step




    package hibernate;

    * @author isaac
    public class TelefonoCliente {

    /** Creates a new instance of TelefonoCliente */

    private String numeroTelefonico;
    private Integer cveTelefono;

    public Integer getCveTelefono() {
    return cveTelefono;

    public void setCveTelefono(Integer cve) {
    cveTelefono = cve;

    public String getNumeroTelefonico() {
    return numeroTelefonico;

    * @param string Sets the Email
    public void setNumeroTelefonico(String string) {
    numeroTelefonico = string;


  3. sushant

    I am new for hibernate and this is very helpful. And this is very easy to understand.

  4. Takao Kimura

    Great!! ThankĀ“s…
    Finally something easy to understand

  5. kukumber

    I am following the same procedure for a sample app.But data’s are not inserting in the PERSON_PHONE table.but other tables data’s are inserting..

    Please hepl me out where i am doing mistake.


  6. Jose

    Great post! Thanks for sharing.

    One question: If PERSON already has 3 PHONE entries in PERSON_PHONE and in code I retrieve that PERSON, I retrieve the PHONE collection and add 1 new phone to it, hibernate executes a DELETE on ALL PERSON_PHONE entries and then does 4 inserts. Is there a way to prevent this behavior and have hibernate only do 1 insert for the new phone?

    Thanks in advance for your help.

  7. Jose


    Do you have the cascade option set to either save-update or all (as the example on the Person class mapping)?

  8. kukumber

    YES,I am using cascade=all inverse=true


    • Vijay vyas

      if your problem still not solved, then Create one mapping between PHONE to PERSON_PHONE Table(either one-to-one, or one-to-many as the case may be.)

  9. Dinakar

    Thanks a ton !!!…. this is the best all-under-one-roof example for many-to-many mapping …… It saved me soo much time….. keep posting such good articles. I also want to know how the mapping would chance if I used ArrayLists to hold objects instead of sets …

  10. Mr. President

    Jose, sorry for the delay in response. I do not have this setup available with me. Will try out your issue some time soon.

  11. Mr. President

    Dinakar, thanks for your comment. Honestly I have not tried using an ArrayList instead of a set, so I do not have any idea, but I guess it should work without any issues.

  12. Excellent post on hibernate relations. Very easy to follow. Most examples I have seen usually use more complicated classes which obscure the objective of the example.

  13. hi this is realy a very good info abt many to many relation thanks i never saw this type live example in so many sites
    realy thanks.

  14. Mr. President

    This is a really delayed response. This is in response to a query from Jose. I am unable to replicate the scenario you mentioned. I have added the following piece of code before the exception catch block in my test code.

    Phone phone3 = new Phone();

    tx = session.beginTransaction();;

    The output generated is:

    Hibernate: select, phone_.contactnumber as contactn2_2_, phone_.phonetype as phonetype2_ from PHONE phone_ where
    Hibernate: select, phone_.contactnumber as contactn2_2_, phone_.phonetype as phonetype2_ from PHONE phone_ where
    Hibernate: insert into PERSON (firstName, lastName, dob, id) values (?, ?, ?, ?)
    Hibernate: insert into PHONE (contactnumber, phonetype, id) values (?, ?, ?)
    Hibernate: insert into PHONE (contactnumber, phonetype, id) values (?, ?, ?)
    Hibernate: insert into PERSON (firstName, lastName, dob, id) values (?, ?, ?, ?)
    Hibernate: insert into PERSON_PHONE (PERSONID, PHONEID) values (?, ?)
    Hibernate: insert into PERSON_PHONE (PERSONID, PHONEID) values (?, ?)
    Hibernate: insert into PERSON_PHONE (PERSONID, PHONEID) values (?, ?)
    Hibernate: insert into PERSON_PHONE (PERSONID, PHONEID) values (?, ?)
    Hibernate: select, phone_.contactnumber as contactn2_2_, phone_.phonetype as phonetype2_ from PHONE phone_ where
    Hibernate: insert into PHONE (contactnumber, phonetype, id) values (?, ?, ?)
    Hibernate: insert into PERSON_PHONE (PERSONID, PHONEID) values (?, ?)

    Jose, is this an appropriate test case or am I doing something wrong?

  15. Srikanth

    Hi friends,

    I already read four books on hibernate but gained very little, confused, frustrated and lost the hope on hibernate.

    But this example gave me lot of hope and confidence.

    My sincere appriciations and thanks to author..

    I am thankfull if he continues his valuable examples like this on every topic in hibernate.

  16. duongtrung

    It’s what i need now!
    Thanks so much. ^-^

  17. moiaz

    xcellent article dude…
    keep posting such articles..
    we need guys like u

    cheers !!!

  18. Thanks a lot….. Very usefull article… Keep dng same.

  19. SJohn

    I have tables agreement, distributor and agreementdistributors.
    The records are not getting saved in agreementdistributors.

    Please help!!!!

    My agreement.hbm.xml looks like below:

    and my Distributor.hbm.xml looks like below:

  20. Mr. President

    Unfortunately SJohn, your xml files did not get copied in your comment. You will have to replace xml tags with their escape character representation for e.g. < becomes <

    A quick suggestion would be to compare my code and yours and identify differences. That should assist you in solving the issue.

  21. Mr. President


    You could use the following URL to convert your XMLs

  22. Maaz Hurzuk

    Thank you very much. Very helpful example.

  23. Vamsi Krishna

    This is very useful for the people who are new for hibernate. Thanks for such post. I have a smiliar many to many relation. Now the new requirment is that the relation between person and phone should not be deleted but only be marked as deleted by adding extra field to Person_phone. Currently i am saving all the three objects person,phone and person_phone manually. Is there any better solution then what i do by using cascade.
    Please help.

  24. Maniyas

    Can we add an additional column in join table PERSON_PHONE table? If yes, how hibernate handles it? Can anyone share the code?

    • Mr. President

      An interesting question. I have not tried it myself. Here are two links which might provide pointers. Hope this helps. URL1, URL2

  25. Thanks for this clear walkthrough. I’m having a really annoying problem though: if i set my dialect to MySQL5InnoDBDialect then i get errors when trying to automatically build my tables. I’m using this little program to do that:

    Configuration config = new Configuration().configure();
    new SchemaUpdate(config).execute(true, true);

    It works however, when I set it to MySQL5Dialect. BUT my other problem is then with a many-to-many mapping (between objects: user and permission), if I include the cascade=”all” and inverse=”true” in their mappings, then the many-to-many table user_permissions never gets populated! I don’t really understand what their use is anyway… as without them, my database tables all work as expected (i get an entry in user_permissions whenever i add to a permission object’s set of users, OR if i add to a user object’s set of permissions).

    BUT (big, and only real problem:) after changing a user’s permission, and successfully saving that change to the DB, when i try to fetch that information, half the time it doesnt execute a query, it just uses the old (stale) information. Any idea why this might be?

    Many Thanks

  26. ggg


  27. shriram.m

    thanks for the clear explanation. Please tell me how to retrieve the values using many to many mapping.(by giving more than one values as input)

    • Mr. President


      Many thanks for your comment. I am unable to understand your requirement. Could you please elaborate on what you are trying to achieve?

  28. shriram

    i am having player class and team class. i want to select the teams(many) which the player is included(one)
    many- one ==>giving the input of players and getting the output of a team(or teams).
    i want an simple example. please provide so that it will be helpful for me to learn the hibernate thoroughly.
    thanks in advance

    • Mr. President


      I think what you are looking for is an example of one-to-many relationship implementation in Hibernate. My earlier post should provide you the answer.

  29. Shriram

    Actually I want to RETRIEVE a single value(one) by giving the input as set(many values). I can retrieve the one to many values by your example. so please give me an example for many to many or many to one retrieval.

    • Mr. President

      I have personally not posted any article on many-to-one relationship. However try this tutorial. Might prove useful.

  30. vercettistate

    thanks dude! you save my life!

  31. MikeBaddeley

    I can’t believe I didn’t stumble across your guide sooner, your directions for one-to-one, one-to-many and many-to-many associations have been spot on and a big help! You present a simple example and cover all the stuff that usually gets bogged down in detail in the Hibernate tutorial. Of course it’s not a be-all and end-all guide but it puts a new Hibernate user on the right track.

  32. AK

    I have the same set up of many to many relationship in Hibernate Spring set up . But while I am trying to saveorUpdate I am getting an exception

    I have many to many relationship between DocumentRepository and DocumentStore Objects

    My Model classes are:

    * @author
    * @hibernate.class table=”document_repository” lazy=”true”
    public class DocumentRepository implements Serializable{
    private Long id;
    private List docStore;

    * column=”id” generator-class=”native” unsaved-value=”null”
    public void setId(Long Id)
    { = id;
    public Long getId()
    return id;

    * @hibernate.list table= “repository_document” cascade=”all” lazy=”false”
    * @hibernate.many-to-many column=”document_id”
    * class=”org.bipsolutions.bx.model.questionnaire.response.DocumentStore”
    * @hibernate.key column=”repository_id”
    * @hibernate.index column=”document_order” generator-class=”native” unsaved-value=”null”
    public List getDocStore() {
    return docStore;

    public void setDocStore(List docStore) {
    this.docStore = docStore;
    * @hibernate.class table=”document_store”
    * */
    public class DocumentStore implements Serializable {

    protected final Log log = LogFactory.getLog(this.getClass());
    private Long id;
    private String fileName;
    private String mimeType;
    private Date upload;
    private Date modified;
    private String hash;
    private Integer documentSize;
    private byte[] document= {};
    private String cachedFilePath;

    * @return Returns the id.
    * column=”id” generator-class=”native”
    * unsaved-value=”null”
    public Long getId() {
    return id;

    public void setId(Long id) { = id;

    * column=”filename” length=”100″
    public String getFileName() {
    return fileName;

    public void setFileName(String fileName) {
    this.fileName = fileName;

    * column=”mime_type” length=”60″
    public String getMimeType() {
    return mimeType;

    public void setMimeType(String mimeType) {
    this.mimeType = mimeType;

    * column=”upload” type=”java.util.Date”
    public Date getUpload() {
    return upload;

    public void setUpload(Date upload) {
    this.upload = upload;

    * column=”modified” type=”java.util.Date”
    public Date getModified() {
    return modified;

    public void setModified(Date modified) {
    this.modified = modified;

    * column=”hash” length=”130″
    public String getHash() {
    return hash;

    public void setHash(String hash) {
    this.hash = hash;
    * column=”document_size”
    * @return
    public int getDocumentSize() {
    if (documentSize != null){
    return documentSize.intValue();
    return 0;

    public void setDocumentSize(Integer documentSize) {
    this.documentSize = documentSize;

    * column=”cached_filepath”
    public String getCachedFilePath() {
    return cachedFilePath;

    public void setCachedFilePath(String cachedFilePath) {
    this.cachedFilePath = cachedFilePath;

    * Type creates a BLOB
    * in DB. Make sure that spring.jar is within hibernate.classpath in file
    * properties.xml
    * column=”document” lazy=”true”
    * type=””
    public byte[] getDocument() {
    return document;

    public void setDocument(byte[] document) {
    this.document = document;

    My DAO Hibernate class to save the repository is
    public class FileRepositoryDaoHibernate extends BaseDaoHibernate implements FileRepositoryDao {
    public UserDao userDao;
    public void setUserDao(UserDao userDao){
    this.userDao = userDao;

    public void saveRepository(DocumentRepository repository)
    System.out.println(“the required method”);


    I have 3 tables that get created in databse
    (1) Document_Repository with Id as the coloumn
    (2)DOcument_store with id as the column along with others.
    (3) the join table repository_document with 3 columns : repository_id,document_id and document_order(key index column)

    When I am trying to save the Repository
    //repository is an instance of DocumentRepository in my class.
    getHibernateTemplate.saveorUpdate(repository) I am getting this error :

    [junit] org.springframework.orm.hibernate3.HibernateSystemException: identifier of an instance of org.bipsolutions.bx.lists.model.DocumentRepository was altered from 41002 to null; nested exception is org.hibernate.HibernateException: identifier of an instance of org.bipsolutions.bx.lists.model.DocumentRepository was altered from 41002 to null

    Can someone please help me over this ?

  33. sumon

    Thanks for your post. But what you will do if you need to add extra column in many to many relational table. Suppose in person_phone table there is also a column called assigned_date, now how you will insert this column data by hibernate?

    • Mr. President


      The answer to your question lies here.

      Refer the FAQ titled “I have a many-to-many association between two tables, but the association table has some extra columns (apart from the foreign keys). What kind of mapping should I use?”

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at The Adventure Journal Theme.


Get every new post delivered to your Inbox.

Join 71 other followers

%d bloggers like this: