Since a many-to-many relationship has “many” on both sides, it can’t be represented with a single foreign key. Instead we use a join table — a table that doesn’t map to an entity itself, used behind the scenes to represent the relationship defined through your objects.
The join table normally contains the primary keys of both entities, and is usually named with the
convention entity1_entity2.
As with one-to-one relationships, you can specify the owner with @JoinColumn, though it matters
less here since Hibernate doesn’t generate anything extra behind the scenes either way. And just
like the other relationship types, you can define this unidirectionally or bidirectionally.
@Entitypublic class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id;
private String name;
// getters and setters}@Entitypublic class Group {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id;
private String name;
private List<User> users;}A unidirectional relationship from Group to User (the user doesn’t know about the group):
@JoinColumn provides the primary key of the current entity (the foreign key for the join
table), and inverseJoinColumns provides the inverse — from the other entity in the relationship.
The entity carrying @JoinTable becomes the owner of the relationship.
// in the group entity@ManyToMany@JoinTable( name = "users_groups", joinColumns = @JoinColumn(name = "group_id"), inverseJoinColumns = @JoinColumn(name = "user_id"))private List<User> users;Without cascading, you’ll have to persist instances of each entity manually.
For a bidirectional relationship, add mappedBy on the non-owning side:
// in the user entity@ManyToMany(mappedBy = "users")private List<Group> groups;This is a bit tricky in practice — you now need to set groups when creating a user, and users
when creating a group, but in exchange you can write queries from either side of the
relationship.
Note that by default, fetch types for many-to-many relationships are LAZY, since they’re
collections.