What is @ManyToMany Mapping in JPA?
@ManyToMany is a JPA annotation used to define a many-to-many relationship between two entity classes.
It means:
βMany records in one table can be associated with many records in another table.β
In simple words:
- Many entities β Many related entities
- Multiple database rows β Multiple related rows
Real-Life Example of Many-to-Many Relationship
Common examples:
- Many students enroll in many courses
- Many users have many roles
- Many products belong to many categories
Database Example
students Table
| id | student_name |
|---|---|
| 1 | Naresh |
courses Table
| id | course_name |
|---|---|
| 101 | Spring Boot |
| 102 | Microservices |
student_courses Table
| student_id | course_id |
|---|---|
| 1 | 101 |
| 1 | 102 |
Here:
- One student can enroll in multiple courses
- One course can contain multiple students
Why @ManyToMany Mapping is Needed
Without relationship mapping:
- Developers must manually manage join tables
- Complex JOIN queries increase
- Object relationships become difficult
@ManyToMany simplifies:
- Relationship management
- Join table handling
- Automatic joins
- Object navigation
Basic @ManyToMany Example
Student Entity
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String studentName;
@ManyToMany
@JoinTable(
name = "student_courses",
joinColumns = @JoinColumn(
name = "student_id"
),
inverseJoinColumns = @JoinColumn(
name = "course_id"
)
)
private List<Course> courses;
}
Course Entity
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String courseName;
}
What is @JoinTable?
@JoinTable specifies the intermediate join table
used for many-to-many relationships.
Join Table Structure
@JoinTable(
name = "student_courses"
)
creates:
student_courses
table automatically.
What are joinColumns?
joinColumns represent the current entity foreign key.
Example
joinColumns = @JoinColumn(
name = "student_id"
)
What are inverseJoinColumns?
inverseJoinColumns represent the related entity foreign key.
Example
inverseJoinColumns = @JoinColumn(
name = "course_id"
)
Generated Database Structure
student_courses Table
CREATE TABLE student_courses (
student_id BIGINT,
course_id BIGINT,
FOREIGN KEY (student_id)
REFERENCES students(id),
FOREIGN KEY (course_id)
REFERENCES courses(id)
)
How @ManyToMany Works Internally
- Hibernate detects relationship annotations
- Join table is created automatically
- Foreign keys are mapped
- JOIN queries are generated automatically
Saving Many-to-Many Data
Course course1 = new Course();
course1.setCourseName("Spring Boot");
Course course2 = new Course();
course2.setCourseName("Microservices");
Student student = new Student();
student.setStudentName("Naresh");
student.setCourses(
List.of(course1, course2)
);
studentRepository.save(student);
Generated SQL Example
INSERT INTO students(student_name)
VALUES ('Naresh');
INSERT INTO courses(course_name)
VALUES ('Spring Boot');
INSERT INTO courses(course_name)
VALUES ('Microservices');
INSERT INTO student_courses(student_id, course_id)
VALUES (1, 101);
INSERT INTO student_courses(student_id, course_id)
VALUES (1, 102);
Fetch Data Example
Student student =
studentRepository.findById(1L).get();
List<Course> courses =
student.getCourses();
Bidirectional Many-to-Many Mapping
Both entities can reference each other.
Student Entity
@Entity
public class Student {
@Id
private Long id;
@ManyToMany
@JoinTable(
name = "student_courses",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private List<Course> courses;
}
Course Entity
@Entity
public class Course {
@Id
private Long id;
@ManyToMany(mappedBy = "courses")
private List<Student> students;
}
What Does mappedBy Mean?
mappedBy specifies:
- The inverse side of the relationship
- Which entity owns the relationship
Owning Side vs Inverse Side
| Type | Description |
|---|---|
| Owning Side | Contains @JoinTable |
| Inverse Side | Contains mappedBy |
Default Fetch Type
The default fetch type for:
@ManyToMany
is:
FetchType.LAZY
LAZY Fetch Example
@ManyToMany(fetch = FetchType.LAZY)
Related data loads only when accessed.
EAGER Fetch Example
@ManyToMany(fetch = FetchType.EAGER)
Related data loads immediately.
LAZY vs EAGER Fetching
| Feature | LAZY | EAGER |
|---|---|---|
| Loading Time | On demand | Immediate |
| Performance | Better | Can be slower |
| Memory Usage | Lower | Higher |
Cascade Types in @ManyToMany
Cascade operations automatically apply persistence actions to related entities.
Cascade Example
@ManyToMany(
cascade = CascadeType.ALL
)
Advantages of @ManyToMany Mapping
- Simplifies many-to-many relationships
- Automatic join table handling
- Easy navigation between entities
- Reduces manual SQL joins
- Improves maintainability
Disadvantages of Improper Mapping
- Complex joins
- N+1 query problem
- Performance overhead
- Large object graphs
- Circular serialization issues
What is N+1 Query Problem?
N+1 problem occurs when:
- One query fetches parent entities
- Additional queries repeatedly fetch related entities
This can reduce performance significantly.
Best Practices for @ManyToMany
- Prefer LAZY fetching
- Use DTOs for API responses
- Avoid unnecessary bidirectional mapping
- Optimize JOIN queries
- Use pagination for large collections
Real-Time Example in Role-Based Security
Security systems often contain:
- Many users β Many roles
Example:
- User can have ADMIN and USER roles
- ADMIN role can belong to many users
This is implemented using:
@ManyToMany
Difference Between @ManyToMany and @OneToMany
| Feature | @ManyToMany | @OneToMany |
|---|---|---|
| Relationship | Many β Many | One β Many |
| Join Table | Required | Not always required |
| Example | Students β Courses | Customer β Orders |
Common Interview Questions on @ManyToMany
What is @ManyToMany mapping?
It defines a many-to-many relationship between entities.
Why is a join table needed?
Because many-to-many relationships require mapping records between two tables.
What is @JoinTable?
It specifies the join table used in many-to-many relationships.
What is the default fetch type for @ManyToMany?
LAZY.
What is mappedBy?
It specifies the inverse side of the relationship.
Conclusion
@ManyToMany is an important relationship annotation
in JPA and Hibernate.
It helps developers:
- Handle complex relationships
- Manage join tables automatically
- Reduce manual SQL joins
- Build scalable enterprise applications
Understanding @ManyToMany is essential for Spring Boot developers
because enterprise applications heavily rely on many-to-many relationships
for proper database design and object mapping.