This tutorial will walk you through the steps of mapping a JPA and Hibernate Many to Many bidirectional entity relationships example with Spring Boot, Spring Data JPA, Lombok, MySQL and Docker

What you will need

  • JDK 8+ or OpenJDK 8+
  • Maven 3+
  • MySQL Server 5+ or Docker CE 18+

Init project structure and dependencies

Project structure

├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── hellokoding
│       │           ├── jpa
│       │           │   ├── book
│       │           │   │   ├──
│       │           │   │   ├──
│       │           │   │   ├──
│       │           │   │   └──
│       │           │   └──
│       │           └── springboot
│       └── resources
│           └──
├── Dockerfile
├── docker-compose.yml
└── pom.xml

Project dependencies

Define JPA Entities and Repositories

Many-To-Many Relationship

Many-to-many relationship refers to the relationship between two entities/tables A and B in which one element/row of A may be linked with many elements of B, and vice versa, one member of B may be linked to many elements of A.

In this example, the book and publisher tables have a many-to-many relationship. One book may be published by many publishers and one publisher may publish many books.

book_publisher is a join table of book and publisher.

book_publisher.book_id is a foreign key references to, book_publisher.publisher_id is a foreign key references to

book_id and publisher_id is also a composite primary key of book_publisher.

Try this example if the join table has extra columns beside two foreign keys
JPA/Hibernate Many To Many Extra Columns Example of Bidirectional Relationship Mapping

Define JPA and Hibernate Entities

JPA Entity is defined with @Entity annotation, represent a table in your database.

@Id declares the entity identifier.

@Column maps the entity's field with the table's column. If @Column is omitted, the field name of the entity will be used as column name by default.

@ManyToMany defines a many-to-many relationship between 2 entities. mappedBy indicates the entity is the inverse of the relationship.

@JoinTable defines the join table of 2 associated entities. If the JoinTable annotation is missing, the default values of the annotation elements apply. The name of the join table is assumed to be the table names of the associated primary tables concatenated together (owning side first) using an underscore.

Spring Data JPA Repository

Spring Data JPA contains some built-in Repository abstracting common functions based on EntityManager to work with database such as findAll, findById, save, delete, deleteById. All we need for this example is extends JpaRepository.

Define properties and creating data

Application Properties

hk-mysql refers to Docker Compose service defined in the below docker-compose.yml file

spring.jpa.hibernate.ddl-auto=create allows JPA/Hibernate auto create database and table schema for you.

On production environment, you may like to disable the DDL Auto feature by using spring.jpa.hibernate.ddl-auto=validate or spring.jpa.hibernate.ddl-auto=none (default). Check out this example as one of the approaches
Database Migration/Evolution Example with Flyway and JPA/Hibernate

Creating data with JPA and Hibernate

Thanks to CascadeType.ALL, associated entity Publisher will be saved at the same time with Book without the need of calling its save function explicitly.

Run the example

Run with Docker

Prepare Dockerfile for Java/Spring Boot application and docker-compose.yml for MySQL Server

Type the below command at the project root directory, make sure your local Docker is running

docker-compose up  

Access to MySQL Server docker container by issuing below bash command and key in hellokoding on Enter password:

docker exec -it hk-mysql mysql -p

Query the schema and data created by JPA/Hibernate based on your mapping

Run with JDK/OpenJDK, Maven and MySQL Server local

Update hk-mysql on to localhost and type the below command at the project root directory

mvn clean spring-boot:run

Source code

See also