| 特性 | Hibernate Session.delete() | JPA EntityManager.remove() |
|---|---|---|
| 外鍵被引用時 | 自動將關聯端外鍵設 NULL,再刪除本體 | 直接執行 DELETE,拋出異常(預設無級聯) |
| 預設級聯行為 | 無(需在映射檔設定 cascade="delete-orphan" 等) | 無(需 @OneToMany(cascade = CascadeType.REMOVE)) |
| 設計哲學 | 「幫開發者處理髒活」 | 「嚴格遵守資料庫完整性,失敗快速」 |
@Entity @Table(name = "JPA_Department")
public class Department implements Serializable {
@Id @GeneratedValue
private Long id;
private String deptName;
@OneToMany(mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true)
private Set persons = new HashSet<>();
// getter/setter 省略
}
@Entity @Table(name = "JPA_Person")
public class Person implements Serializable {
@Id @GeneratedValue
private Integer id;
private String name;
@ManyToOne
@JoinColumn(name = "dept_id")
private Department department;
// getter/setter 省略
}
<class name="Department" table="Department">
<id name="id" column="departId"><generator class="native"/></id>
<property name="deptName"/>
<set name="persons" cascade="all-delete-orphan">
<key column="deptId"/>
<one-to-many class="Person"/>
</set>
</class>
<class name="Person" table="Person">
<id name="id" column="personId"><generator class="native"/></id>
<property name="name"/>
<many-to-one name="department" class="Department" column="deptId"/>
</class>
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Department dept = em.find(Department.class, 3L); // 該部門下有員工
em.remove(dept); // 拋出 EntityExistsException / ConstraintViolationException
em.getTransaction().commit();
Session session = sf.getCurrentSession();
session.getTransaction().begin();
Department dept = (Department) session.load(Department.class, 2L);
session.delete(dept); // 自動把員工 dept_id 設 NULL,再刪部門
session.getTransaction().commit();
delete() 會檢查關聯集合,若配置 cascade 或 inverse="true",自動發出 UPDATE person SET dept_id=NULL WHERE dept_id=? 再 DELETE FROM department WHERE id=?。remove() 僅對實體本身發 DELETE,不自動處理關聯端,除非明確宣告 cascade = CascadeType.REMOVE 或 orphanRemoval = true。@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true),行為與 Hibernate 對齊。ON DELETE SET NULL 或 ON DELETE CASCADE 作為最後防線。dept.getPersons().clear(),再 remove(dept),語意最清晰。理解這個差異,能避免從 Hibernate 遷移 JPA 時的「刪不掉」驚魂,也能在代碼審查時精準指出資料完整性風險。