1. 一對多映射
1.1 JavaWeb 一對多建表原則
- 多方表的外鍵指向一方表的主鍵;
1.2 編寫一對多的 JavaBean
// 客戶(一方)和聯系人(多方)
// 客戶(一方) JavaBean
public class Customer{
private Long cust_id;
private String cust_name;
private Long cust_create_id;
...
// 關聯多方
// Hibernate 框架默認的集合是 Set 集合,該集合必須要自己手動初始化
private Set<Linkman> linkmans = new HashSet<Linkman>();
......
}
// 聯系人(多方) JavaBean
public class Linkman{
private Long lkm_id;
private String lkm_name;
private String lkm_gender;
...
// 關聯一方
// 編寫一個對象, 不需要自己 new
private Customer customer;
....
}
1.3 編寫一對多的映射配置文件
// Customer.hbm.xml (客戶映射配置)
<class name="com.itheima.domain.Customer" table="cst_customer">
<id name="cust_id" column="cust_id">
<generator class="native"/>
</id>
<property name="cust_name" column="cust_name"/>
<property name="cust_create_id" column="cust_create_id"/>
...
// 關聯的配置(一方)
// name 表示集合的名稱
<set name="linkmans">
<key column="lkm_cust_id"/> // column 外鍵的字段
<one-to-many class="com.itheima.domain.Linkman"/>
</set>
</class>
// Linkman.hbm.xml (聯系人映射配置)
<class name="com.itheima.doamin.Linkman" table="cst_linkman">
<id name="lkm_id" column="lkm_id">
<generator class="native"/>
</id>
<property name="lkm_name" column="lkm_name"/>
<property name="lkm_gender" column="lkm_gender"/>
...
// 關聯的配置(多方)
// name 當前 JavaBean 中的屬性
// class 屬性的全路徑
// column 外鍵的字段(表)
<many-to-one name="customer" class="com.itheima.domain.Customer" column="lkm_cust_id"/>
</class>
2. 保存客戶和聯系人的數據
2.1 雙向關聯的方式保存數據
public class Demo{
public void fun(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
// 創建客戶
Customer c1 = new Customer();
c1.setCust_name("張三");
// 創建聯系人
Linkman lk1 = new Linkman();
lk1.setLkm_name("熊大");
Linkman lk2 = new Linkman();
lk2.setLkm_name("熊二");
// 雙向關聯
c1.getLinkmans().add(lk1);
c1.getLinkmans().add(lk2);
lk1.setCustomer(c1);
lk2.setCustomer(c1);
session.save(c1);
session.save(lk1);
session.save(lk2);
tr.commit();
}
}
2.2 級聯保存
- 級聯保存:保存一方,同時可以把關聯的對象也保存到數據庫中!
- 級聯保存是有方向性的.例如,保存客戶時,級聯保存聯系人;或者,保存聯系人時,級聯保存客戶;
- 使用
cascade="save-update"
// 保存客戶,級聯保存聯系人
// 需要在客戶 Customer.hbm.xml 中配置
<set name="linkmans" cascade="save-update">
<key column="lkm_cust_id"/>
<one-to-many class="com.itheima.domain.Linkman"/>
</set>
pulic class Demo{
pulic class fun(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
// 創建客戶
Customer c1 = new Customer();
c1.setCust_name("張三");
// 創建聯系人
Linkman l1 = new Linkman();
l1.setLkm_name("熊大");
Linkman l2 = new Linkman();
l2.setLkm_name("熊二");
// 單向關聯
c1.getLinkmans().add(l1);
c1.getLinkmans().add(l2);
l1.setCustomer(c1); // 此處,如果沒有,報錯.
l2.setCustomer(c1); // 此處,如果沒有,報錯.
// 保存客戶
session.save(c1);
tr.commit();
}
}
// 保存聯系人,級聯保存客戶
// 需要在聯系人 Linkman.hbm.xml 中配置
<many-to-one name="customer" class="cn.itheima.domain.Customer"
column="lkm_cust_id" cascade="save-update"/>
public class Demo{
public class fun(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
// 創建客戶
Customer c1 = new Customer();
c1.setCust_name("張三");
// 創建聯系人
Linkman l1 = new Linkman();
l1.setLkm_name("熊大");
Linkman l2 = new Linkman();
l2.setLkm_name("熊二");
l1.setCustomer(c1);
l2.setCustomer(c2);
// 保存聯系人
session.save(l1);
session.save(l2);
tr.commit();
}
}
2.3 級聯刪除
- 級聯刪除也是有方向性的;
// 刪除客戶時, 刪除聯系人(一方級聯刪除多方), 配置 Customer.hbm.xml
<set name="linkmans" cascade="delete">
<key column="lkm_cust_id"/>
<one-to-many class="cn.itheima.domain.Linkman"/>
</set>
2.4 級聯的取值和孤兒刪除
1. 級聯的取值(cascade 的取值)
none
: 不使用級聯;save-update
: 級聯保存或更新;delete
: 級聯刪除;delete-orphan
: 孤兒刪除(只能應用在一對多關系);all
: 除了delete-orphan
的所有情況;all-delete-orphan
: 包含了delete-orphan
的所有情況;
2. 孤兒刪除
- 只有在一對多的環境下才有孤兒刪除;
- 在一對多的關系中,可以將一方認為是父方,將多的一方認為是子方;孤兒刪除,就是在解除了父子關系的時候,
將子方記錄直接刪除;
2.5 讓某一方放棄外鍵的維護,為多對多映射做准備: inverse
- 在修改客戶和聯系人的關系時,進行雙向關聯,雙方都會維護外鍵,會產生多余的 SQL 語句.
- 產生的原因: session 的一級緩存中的快照機制,會讓雙方都更新數據庫,產生了多余的 SQL 語句.
- 如果不想產生多余的 SQL 語句,那么需要一方來放棄外鍵的維護, 由多方來維護!
// 放棄外鍵維護
// Customer.hbm.xml 進行如下配置
<set name="linkman" inverse="true"> // true 表示放棄; 默認值為 false
<key column="lkm_cust_id"/>
<one-to-many class="com.itheima.domain.Linkman"/>
</set>
3. 多對多映射
3.1 多對多建表原則
- 以用戶和角色為例,需要創建三張表: 用戶表,角色表,中間表(維護前面兩個表的數據);
- 使用Hibernate 框架,只要編寫兩個 JavaBean 以及對應的映射配置文件,中間表會自動生成;
- 多對多映射關系中,必須有一方放棄外鍵維護;
// 編寫用戶和角色的 JavaBean
// 用戶的 JavaBean
public class User{
private Long user_id;
private String user_name;
private String user_pwd;
...
private Set<Role> roles = new HashSet<Role>();
}
// 角色的 JavaBean
public class Role{
private Long role_id;
private String role_name;
private String role_desc;
private Set<User> users = new HashSet<User>();
}
// 編寫映射配置文件
// 用戶的映射配置文件, User.hbm.xml
<class name="com.itheima.domain.User" table="sys_user">
<id name="user_id" column="user_id">
<generator class="native"/>
</id>
<property name="user_name" column="user_name"/>
<property name="user_pwd" column="user_pwd"/>
// 配置多對多
// name 表示集合的名稱
// table 表示中間表的名稱
<set name="roles" table="sys_user_role" inverse="true">
// 當前對象在中間表的外鍵名稱
<key column="user_id"/>
// class : 集合中存入的對象,對象的全路徑
// column: 集合中對象,在中間表的外鍵名稱
<many-to-many class="com.itheima.domain.Role" column="role_id"/>
</set>
</class>
// 角色的映射配置文件, Role.hbm.xml
<class name="com.itheima.domain.Role" table="sys_role">
<id name="role_id" column="role_id">
<generator class="native"/>
</id>
<property name="role_name" column="role_name"/>
<property name="role_desc" column="role_desc"/>
<set name="users" table="sys_user_role">
<key column="role_id"/>
<many-to-many class="com.itheima.domain.User" column="user_id"/>
</set>
</class>
參考資料