多對多關係在關聯式資料庫中無法直接表達,必須引入**中介表** 將其拆解為兩個一對多關係。

CREATE TABLE user (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL DEFAULT ''
);
CREATE TABLE server (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
address VARCHAR(100) NOT NULL DEFAULT ''
);
CREATE TABLE user_server (
user_id INT(11),
server_id INT(11)
);
public class User {
private Integer id;
private String name;
private Set<Server> servers = new HashSet<>();
// getter/setter ...
}
public class Server {
private Integer id;
private String address;
private Set<User> users = new HashSet<>();
// getter/setter ...
}
<many-to-many><set name="servers" table="user_server" cascade="save-update">
<key column="user_id"/>
<many-to-many class="com.hb3.pack_19.model.Server" column="server_id"/>
</set>
<set name="users" table="user_server" inverse="true" cascade="save-update">
<key column="server_id"/>
<many-to-many class="com.hb3.pack_19.model.User" column="user_id"/>
</set>
核心原則: 雙向關聯必須指定一方 inverse="true",避免重複維護中介表導致效能損耗或資料不一致。通常由 **集合端(這裡是 User.servers)負責維護**。
Server s1 = new Server(); s1.setAddress("PC-219"); s1.setUsers(new HashSet<>());
Server s2 = new Server(); s2.setAddress("PC-220"); s2.setUsers(new HashSet<>());
Server s3 = new Server(); s3.setAddress("PC-221"); s3.setUsers(new HashSet<>());
User u1 = new User(); u1.setName("shenbin"); u1.setServers(new HashSet<>());
User u2 = new User(); u2.setName("chenyan"); u2.setServers(new HashSet<>());
// 雙向建立關聯(雙邊都要 set,否則記憶體中物件圖不一致)
u1.getServers().add(s1); u1.getServers().add(s2); u1.getServers().add(s3);
s1.getUsers().add(u1); s2.getUsers().add(u1); s3.getUsers().add(u1);
u2.getServers().add(s1); u2.getServers().add(s3);
s1.getUsers().add(u2); s3.getUsers().add(u2);
Transaction tx = session.beginTransaction();
session.save(u1); // 因 cascade="save-update",關聯的 Server 及中介表資料會一併存入
session.save(u2);
tx.commit();
雖然 Hibernate 支援多對多映射,但**中介表會導致查詢需多一次 JOIN**,寫入時也需維護三張表。**實務上建議盡量避免多對多**,改用兩個一對多關聯,並在中介表建立實體類別,獲得更靈活的控制與更佳效能。