Open In App

JPA - Many-To-Many Mapping

Last Updated : 07 Nov, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

In Java Persistence API (JPA), a Many-To-Many Mapping defines a relationship where multiple instances of one entity are associated with multiple instances of another entity. In relational databases, this is typically implemented using a join table that contains foreign keys referencing the primary keys of both entities.

Understanding Many-to-Many Mapping

In a many-to-many relationship:

  • One Student can enroll in multiple Courses.
  • One Course can have multiple Students.

In JPA, this is achieved using the @ManyToMany annotation, often combined with @JoinTable to define the linking table.

Steps to Implement Many-To-Many Mapping in JPA

1. Define the Entities

We’ll create two entities: Student and Course. Each entity maintains a collection referencing the other side.

Student Entity:

Java
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToMany(mappedBy = "students")
    private Set<Course> courses = new HashSet<>();

    // Getters and Setters
}
  • The @ManyToMany(mappedBy = "students") makes this side the inverse side of the relationship.
  • The courses field maps to the owning side defined in Course.

Course Entity:

Java
@Entity
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToMany
    @JoinTable(
        name = "course_student",
        joinColumns = @JoinColumn(name = "course_id"),
        inverseJoinColumns = @JoinColumn(name = "student_id")
    )
    private Set<Student> students = new HashSet<>();

    // Getters and Setters
}
  • The @JoinTable defines the join table name (course_student).
  • joinColumns represents the foreign key for Course.
  • inverseJoinColumns represents the foreign key for Student.

2. Configure the Persistence Unit

In persistence.xml, configure database connection and entity classes.

XML
<persistence xmlns="https://jakarta.ee/xml/ns/persistence/"
             xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence/ https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
             version="3.0">
    <persistence-unit name="jpa-example">
        <class>model.Student</class>
        <class>model.Course</class>
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/example"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value=""/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>
    </persistence-unit>
</persistence>

This file registers entity classes and sets up the database connectivity for JPA and Hibernate.

Project Structure:

Project Structure

3. Create Service Layer Classes

StudentService.java:

Java
package service;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityTransaction;
import model.Student;
import java.util.List;

public class StudentService {
    private final EntityManager entityManager;

    public StudentService(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public List<Student> getAllStudents() {
        return entityManager.createQuery("SELECT s FROM Student s", Student.class).getResultList();
    }

    public Student saveStudent(Student student) {
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        entityManager.persist(student);
        transaction.commit();
        return student;
    }

    public Student getStudentById(Long id) {
        return entityManager.find(Student.class, id);
    }
}

CourseService.java:

Java
package service;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityTransaction;
import model.Course;
import java.util.List;

public class CourseService {
    private final EntityManager entityManager;

    public CourseService(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public List<Course> getAllCourses() {
        return entityManager.createQuery("SELECT c FROM Course c", Course.class).getResultList();
    }

    public Course saveCourse(Course course) {
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        entityManager.persist(course);
        transaction.commit();
        return course;
    }

    public Course getCourseById(Long id) {
        return entityManager.find(Course.class, id);
    }
}

These classes provide reusable methods for persisting and retrieving Student and Course entities.

4. Create the Main Application

File: MainApplication.java

Java
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import model.Course;
import model.Student;
import service.CourseService;
import service.StudentService;
import java.util.List;

public class MainApplication {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-example");

        CourseService courseService = new CourseService(emf.createEntityManager());
        StudentService studentService = new StudentService(emf.createEntityManager());

        // Create courses
        Course javaCourse = new Course();
        javaCourse.setName("Java");
        courseService.saveCourse(javaCourse);

        Course pythonCourse = new Course();
        pythonCourse.setName("Python");
        courseService.saveCourse(pythonCourse);

        // Create students
        Student mahesh = new Student();
        mahesh.setName("Mahesh Kadambala");
        mahesh.getCourses().add(javaCourse);
        mahesh.getCourses().add(pythonCourse);
        studentService.saveStudent(mahesh);

        Student eswar = new Student();
        eswar.setName("Eswar Beta");
        eswar.getCourses().add(javaCourse);
        studentService.saveStudent(eswar);

        // Retrieve and print data
        List<Course> courses = courseService.getAllCourses();
        System.out.println("Courses:");
        for (Course c : courses) {
            System.out.println(c.getId() + ": " + c.getName());
        }

        List<Student> students = studentService.getAllStudents();
        System.out.println("\nStudents:");
        for (Student s : students) {
            System.out.println(s.getId() + ": " + s.getName());
            System.out.println("Enrolled Courses:");
            for (Course c : s.getCourses()) {
                System.out.println(" - " + c.getName());
            }
        }

        emf.close();
    }
}
  • Creates and saves course and student records.
  • Establishes many-to-many links by adding entities to each other’s collection.
  • Prints out all stored records from the database.

5. Maven Configuration (pom.xml)

XML
<dependencies>
    <dependency>
        <groupId>org.hibernate.orm</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>6.0.2.Final</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>3.0.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.28</version>
    </dependency>
</dependencies>

6. Running the Application

Steps:

  1. Start your MySQL server.
  2. Run MainApplication.java.
  3. The program will automatically create tables - student, course, and the join table course_student.

Output in the console:

Output Screen

Article Tags :

Explore