Hibernate框架筆記03_表操作_多對多配置
1. 數(shù)據(jù)庫表與表之間的關(guān)系
1.1 一對多關(guān)系
-
什么樣的關(guān)系屬于一對多航徙?
- 一個部門對應(yīng)多個員工,一個員工只能屬于某一個部門
- 一個客戶對應(yīng)多個聯(lián)系人持际,一個聯(lián)系人只能屬于某一個客戶
-
一對多的建表原則:在多的一方創(chuàng)建外鍵指向一的一方的主鍵
一對多建表原則
1.2 多對多關(guān)系
-
什么樣的關(guān)系屬于多對多?
- 一個學(xué)生可以選擇多門課程,一門課程可以被多個學(xué)生選擇
- 一個用戶可以選擇多個角色玻佩,一個角色可以被多個用戶選擇
-
多對多的建表原則:多對多建原則:創(chuàng)建一個中間表荷科,中間表至少有兩個字段分別作為外鍵指向多對多雙方的主鍵唯咬。
多對多建表原則
1.3 一對一關(guān)系【了解】
- 什么樣的關(guān)系屬于一對一?
- 一個公司只能有一個注冊地址畏浆,一個注冊地址只能被一個公司注冊胆胰。
- 唯一外鍵對應(yīng):假設(shè)是一對多的關(guān)系,需要在多的一方創(chuàng)建外鍵指向一的一方的主鍵刻获,將外鍵設(shè)置為unique
- 主鍵對應(yīng):讓某個表的主鍵作為另一個表的主鍵蜀涨。
2. Hibernate的一對多關(guān)聯(lián)映射
2.1 創(chuàng)建一個項目,引入相關(guān)jar包
2.2. 創(chuàng)建數(shù)據(jù)庫和表
創(chuàng)建數(shù)據(jù)庫蝎毡,新建兩張表
-
customer表crm_cst_customer.sql
CREATE TABLE `cst_customer` ( `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客戶編號(主鍵)', `cust_name` varchar(32) NOT NULL COMMENT '客戶名稱(公司名稱)', `cust_source` varchar(32) DEFAULT NULL COMMENT '客戶信息來源', `cust_industry` varchar(32) DEFAULT NULL COMMENT '客戶所屬行業(yè)', `cust_level` varchar(32) DEFAULT NULL COMMENT '客戶級別', `cust_phone` varchar(64) DEFAULT NULL COMMENT '固定電話', `cust_mobile` varchar(16) DEFAULT NULL COMMENT '移動電話', PRIMARY KEY (`cust_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-
LinkMan表crm_cst_linkman.sql
CREATE TABLE `cst_linkman` ( `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '聯(lián)系人編號(主鍵)', `lkm_name` varchar(16) DEFAULT NULL COMMENT '聯(lián)系人姓名', `lkm_cust_id` bigint(32) NOT NULL COMMENT '客戶id', `lkm_gender` char(1) DEFAULT NULL COMMENT '聯(lián)系人性別', `lkm_phone` varchar(16) DEFAULT NULL COMMENT '聯(lián)系人辦公電話', `lkm_mobile` varchar(16) DEFAULT NULL COMMENT '聯(lián)系人手機', `lkm_email` varchar(64) DEFAULT NULL COMMENT '聯(lián)系人郵箱', `lkm_qq` varchar(16) DEFAULT NULL COMMENT '聯(lián)系人qq', `lkm_position` varchar(16) DEFAULT NULL COMMENT '聯(lián)系人職位', `lkm_memo` varchar(512) DEFAULT NULL COMMENT '聯(lián)系人備注', PRIMARY KEY (`lkm_id`), KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`), CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
兩個表之間的關(guān)系
2.3 創(chuàng)建實體
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
// 通過ORM方式表示:一個客戶對應(yīng)多個聯(lián)系人
// 放置的是多的一方的集合厚柳。Hibernate默認(rèn)使用的是Set集合
private Set<LinkMan> linkMans = new HashSet<LinkMan>();
//get/set方法
public class LinkMan {
private Long lkm_id;
private String lkm_name;
private String lkm_gender;
private String lkm_phone;
private String lkm_mobile;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo;
// 通過ORM方式表示:一個聯(lián)系人只能屬于某一個客戶
// 放置的是一的一方的對象
private Customer customer;
//set/get方法
2.4 創(chuàng)建映射文件
有幾個實體就需要幾個映射文件
-
Customer.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.itzhouq.hibernate.domain.Customer" table="cst_customer"> <!-- 建立OID與主鍵映射 --> <id name="cust_id" column="cust_id"> <generator class="native"></generator> </id> <!-- 建立普通屬性和數(shù)據(jù)庫字段映射 --> <property name="cust_name" column="cust_name"></property> <property name="cust_source" column="cust_source"></property> <property name="cust_industry" column="cust_industry"></property> <property name="cust_level" column="cust_level"></property> <property name="cust_phone" column="cust_phone"></property> <property name="cust_mobile" column="cust_mobile"></property> <!-- 配置一對多的映射:放置的多的一方的集合 --> <!-- set標(biāo)簽: * name:多的一方的對象集合的屬性名稱 --> <set name="linkMans"> <!-- column多的一方的外鍵的名稱 --> <key column="lkm_cust_id"></key> <!-- class:多的一方的類的全限定名 --> <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/> </set> </class> </hibernate-mapping>
-
LinkMan.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.itzhouq.hibernate.domain.LinkMan" table="cst_linkman"> <!-- 建立OID與主鍵映射 --> <id name="lkm_id" column="lkm_id"> <generator class="native"></generator> </id> <!-- 建立普通屬性與表字段映射 --> <property name="lkm_name"/> <property name="lkm_gender"/> <property name="lkm_phone"/> <property name="lkm_mobile"/> <property name="lkm_email"/> <property name="lkm_qq"/> <property name="lkm_position"/> <property name="lkm_memo"/> <!-- 配置多對一的關(guān)系:放置的是一的一方的對象 --> <!-- many-to-one標(biāo)簽 * name:一的一方的對象的屬性名稱 *class:一的一方的類的全限定名 column:在多的一方的表的外鍵的名稱 --> <many-to-one name="customer" class="com.itzhouq.hibernate.domain.Customer" column="lkm_cust_id"/> </class> </hibernate-mapping>
2.5 創(chuàng)建核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 連接數(shù)據(jù)庫的基本參數(shù) -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate_day03</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">2626</property>
<!-- 配置Hibernate的方言(可選的) -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 打印SQL(可選的) -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化SQL(可選的) -->
<property name="hibernate.format_sql">true</property>
<!-- 自動創(chuàng)建表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 配置C3P0連接池 -->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!--在連接池中可用的數(shù)據(jù)庫連接的最少數(shù)目 -->
<property name="c3p0.min_size">5</property>
<!--在連接池中所有數(shù)據(jù)庫連接的最大數(shù)目 -->
<property name="c3p0.max_size">20</property>
<!--設(shè)定數(shù)據(jù)庫連接的過期時間,以秒為單位,
如果連接池中的某個數(shù)據(jù)庫連接處于空閑狀態(tài)的時間超過了timeout時間,就會從連接池中清除 -->
<property name="c3p0.timeout">120</property>
<!--每3000秒檢查所有連接池中的空閑連接 以秒為單位-->
<property name="c3p0.idle_test_period">3000</property>
<!-- 設(shè)置事務(wù)的隔離級別 -->
<property name="hibernate.connection.isolation">4</property>
<!-- 配置當(dāng)前線程綁定的Session -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 配置映射文件 -->
<mapping resource="com/itzhouq/hibernate/domain/Customer.hbm.xml"/>
<mapping resource="com/itzhouq/hibernate/domain/LinkMan.hbm.xml"/>
</session-factory>
</hibernate-configuration>
2.6 引入工具類和日志
2.7 編寫測試
package com.itzhouq.hibernate.demo;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.itzhouq.hibernate.domain.Customer;
import com.itzhouq.hibernate.domain.LinkMan;
import com.itzhouq.hibernate.utils.HibernateUtils;
/*
* 一對多的測試類
*/
public class Demo1 {
@Test
// 保存兩個聯(lián)系人,三個客戶
public void test() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 創(chuàng)建兩個客戶
Customer customer1 = new Customer();
customer1.setCust_name("王東");
Customer customer2 = new Customer();
customer2.setCust_name("李希");
// 創(chuàng)建三個聯(lián)系人
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("鳳姐");
LinkMan linkMan2 = new LinkMan();
linkMan2.setLkm_name("如花");
LinkMan linkMan3 = new LinkMan();
linkMan3.setLkm_name("王冬冬");
// 設(shè)置關(guān)系
linkMan1.setCustomer(customer1);
linkMan2.setCustomer(customer1);
linkMan3.setCustomer(customer2);
customer1.getLinkMans().add(linkMan1);
customer1.getLinkMans().add(linkMan2);
customer2.getLinkMans().add(linkMan3);
// 保存數(shù)據(jù)
session.save(customer1);
session.save(customer2);
session.save(linkMan1);
session.save(linkMan2);
session.save(linkMan3);
transaction.commit();
}
}
2.8 一對多的級聯(lián)操作
- 級聯(lián):級聯(lián)指的是沐兵,操作一個對象時草娜,是否會同時操作其關(guān)聯(lián)的對象。
- 級聯(lián)是有方向性:
- 操作一的一方的時候痒筒,是否操作到多的一方
- 操作多的一方的時候宰闰,是否操作到一的一方
2.8.1 級聯(lián)保存或級聯(lián)刪除
-
保存客戶茬贵,級聯(lián)聯(lián)系人
- 操作的主體是客戶對象,需要在Customer.hbm.xml中進(jìn)行配置
<!-- set標(biāo)簽: * name:多的一方的對象集合的屬性名稱 * cascade:級聯(lián) --> <set name="linkMans" cascade="save-update"> <!-- column多的一方的外鍵的名稱 --> <key column="lkm_cust_id"></key> <!-- class:多的一方的類的全限定名 --> <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/> </set>
@Test
/**
* 級聯(lián)保存或更新操作
* 保存客戶級聯(lián)聯(lián)系人,操作的主體是客戶對象移袍,需要在Customer.hbm.xml中進(jìn)行配置
*/
public void test2() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("趙紅");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("如花");
customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);
session.save(customer);
transaction.commit();
}
-
保存聯(lián)系人解藻,級聯(lián)客戶
-
操作的主體是聯(lián)系人對象,需要在LinkMan.hbm.xml中進(jìn)行配置
<many-to-one name="customer" cascade="save-update" class="com.itzhouq.hibernate.domain.Customer" column="lkm_cust_id"/>
@Test /** * 級聯(lián)保存或更新操作 * 保存客戶級聯(lián)聯(lián)系人,操作的主體是客戶對象葡盗,需要在LinkMan.hbm.xml中進(jìn)行配置 */ public void test2() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("趙斌"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("思域"); customer.getLinkMans().add(linkMan); linkMan.setCustomer(customer); session.save(linkMan); transaction.commit(); }
-
-
測試對象導(dǎo)航
@Test /** * 測試對象的導(dǎo)航 * 前提:一對多的雙方都設(shè)置cascade="save-update" */ public void test3() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("趙斌"); LinkMan linkMan1 = new LinkMan(); linkMan1.setLkm_name("鳳姐"); LinkMan linkMan2 = new LinkMan(); linkMan2.setLkm_name("如花"); LinkMan linkMan3 = new LinkMan(); linkMan3.setLkm_name("芙蓉"); linkMan1.setCustomer(customer); customer.getLinkMans().add(linkMan2); customer.getLinkMans().add(linkMan3); // 雙方都設(shè)置了cascade //session.save(linkMan1); // 發(fā)送幾條insert語句 4條 //session.save(customer); // 發(fā)送幾條insert語句 3條 session.save(linkMan2); // 發(fā)送幾條insert語句 1條 transaction.commit(); }
2.8.2 級聯(lián)刪除
級聯(lián)刪除:級聯(lián)刪除一遍的時候螟左,同時將另一方的數(shù)據(jù)也一并刪除
刪除客戶的時候級聯(lián)刪除聯(lián)系人
-
刪除的主體是客戶,需要在Custoemr.hbm.xml中配置
<set name="linkMans" cascade="save-update,delete"> <!-- column多的一方的外鍵的名稱 --> <key column="lkm_cust_id"></key> <!-- class:多的一方的類的全限定名 --> <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/> </set>
@Test
/**
* 級聯(lián)刪除
* 刪除客戶級聯(lián)刪除聯(lián)系人觅够,刪除的主體是客戶胶背,需要在Custoemr.hbm.xml中配置
*/
public void test4() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 沒有設(shè)置級聯(lián),默認(rèn)情況:修改聯(lián)系人的外鍵喘先,刪除客戶
//Customer customer = session.get(Customer.class, 1L);
//session.delete(customer);
// 刪除客戶钳吟,同時刪除聯(lián)系人 <set name="linkMans" cascade="save-update,delete">
Customer customer = session.get(Customer.class, 1L);
session.delete(customer);
transaction.commit();
}
- 刪除聯(lián)系人級聯(lián)刪除客戶(基本不用)
2.8.3 inverse的配置
-
一對多設(shè)置了雙向關(guān)聯(lián)會產(chǎn)生多余的SQL語句
@Test /** * 將2號聯(lián)系人原來歸1號聯(lián)系人,現(xiàn)在改為2號客戶 */ public void test5() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 查詢2號聯(lián)系人 LinkMan linkMan = session.get(LinkMan.class, 2L); //查詢2號客戶 Customer customer = session.get(Customer.class, 2L); //雙向的關(guān)聯(lián) linkMan.setCustomer(customer); customer.getLinkMans().add(linkMan); //發(fā)送了兩次update語句窘拯,對外鍵修改了兩次 //持久態(tài)對象自動更新 transaction.commit(); }
-
分析
雙向維護(hù) -
解決多余的SQL語句
- 單向維護(hù)
- 使一方放棄外鍵維護(hù)權(quán):一的一方放棄红且。在配置文件Customer.hbm.xml中的
set
上配置inverse="true"
-
區(qū)分cascade和inverse
cascade是操作關(guān)聯(lián)對象的,比如客戶存到數(shù)據(jù)庫了涤姊,客戶關(guān)聯(lián)的聯(lián)系人也會存到數(shù)據(jù)庫
-
但是有沒有外鍵是由inverse控制的
@Test /** * 區(qū)分cascade和inverse的區(qū)別 */ public void test6() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("李斌"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("鳳姐"); customer.getLinkMans().add(linkMan); //條件在Customer.hbm.xml上的set中配置了cascade="save-update" inverse="true" session.save(customer); // 客戶回插入到數(shù)據(jù)庫暇番,聯(lián)系人也會插入到數(shù)據(jù)庫,但是外鍵為null transaction.commit(); }
Customer.hbm.xml相關(guān)配置
<!-- set標(biāo)簽: * name:多的一方的對象集合的屬性名稱 * cascade:級聯(lián) * inverse: 是否放棄外鍵約束思喊,true表示放棄外鍵約束 --> <set name="linkMans" cascade="save-update,delete" inverse="true"> <!-- column多的一方的外鍵的名稱 --> <key column="lkm_cust_id"></key> <!-- class:多的一方的類的全限定名 --> <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/> </set>
3. Hibernate的多對多關(guān)聯(lián)映射
3.1 HIbernate多對多的關(guān)系的配置
3.1.1 創(chuàng)建表
- 用戶表
CREATE TABLE `sys_user` (
`user_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '用戶id',
`user_code` VARCHAR(32) COMMENT '用戶賬號',
`user_name` VARCHAR(64) COMMENT '用戶名稱',
`user_password` VARCHAR(32) COMMENT '用戶密碼',
`user_state` CHAR(1) COMMENT '1:正常,0:暫停',
PRIMARY KEY (`user_id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
- 角色表
CREATE TABLE `sys_role` (
`role_id` BIGINT(32) NOT NULL AUTO_INCREMENT,
`role_name` VARCHAR(32) COMMENT '角色名稱',
`role_memo` VARCHAR(128) DEFAULT NULL COMMENT '備注',
PRIMARY KEY (`role_id`)
) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
- 中間表
CREATE TABLE `sys_user_role` (
`role_id` BIGINT(32) NOT NULL COMMENT '角色id',
`user_id` BIGINT(32) NOT NULL COMMENT '用戶id',
PRIMARY KEY (`role_id`,`user_id`),
KEY `FK_user_role_user_id` (`user_id`),
CONSTRAINT `FK_user_role_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_user_role_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=INNODB DEFAULT CHARSET=utf8;
3.1.2 創(chuàng)建實體
- 用戶實體User
public class User {
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private String user_state;
// 設(shè)置多對多關(guān)系:表示一個用戶選擇多個角色
// 放置的是角色的集合
private Set<Role> roles = new HashSet<Role>();
//set/get方法
- 角色實體Role
public class Role {
private Long role_id;
private String role_name;
private String role_memo;
// 一個角色被多個用戶選擇
// 放置的是用戶的集合
private Set<User> users = new HashSet<User>();
//set/get方法
3.1.3 創(chuàng)建映射
- 用戶的映射
User.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.itzhouq.hibernate.domain.User" table="sys_user">
<!-- 建立主鍵與OID的映射 -->
<id name="user_id" column="user_id">
<generator class="native"/>
</id>
<!-- 建立普通屬性與字段映射 -->
<property name="user_code" column="user_code"/>
<property name="user_name" column="user_name"/>
<property name="user_password" column="user_password"/>
<property name="user_state" column="user_state"/>
<!-- 建立角色的多對多的映射關(guān)系-->
<!-- set
* name:對方的集合的屬性名
* table:多對多的關(guān)系需要使用中間表壁酬,放的是中間表的名稱。
-->
<set name="roles" table="sys_user_role">
<!-- key標(biāo)簽中column指的是當(dāng)前對象對應(yīng)的中間表的外鍵的名稱 -->
<!-- many-to-many標(biāo)簽:
* class : 對方的類的全路徑
* column : 對方的對象在中間表中的外鍵的名稱
-->
<key column="user_id"/>
<many-to-many class="com.itzhouq.hibernate.domain.Role" column="role_id"/>
</set>
</class>
</hibernate-mapping>
- 角色的映射
Role.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.itzhouq.hibernate.domain.Role" table="sys_role">
<!-- 建立主鍵與OID的屬性 -->
<id name="role_id" column="role_id">
<generator class="native"/>
</id>
<!-- 將普通屬性與字段映射-->
<property name="role_name" column="role_name"/>
<property name="role_memo" column="role_memo"/>
<!--inverse="true",Role一方放棄了外鍵的維護(hù)權(quán) -->
<set name="users" table="sys_user_role" inverse="true">
<key column="role_id"/>
<many-to-many class="com.itzhouq.hibernate.domain.User" column="user_id"/>
</set>
</class>
</hibernate-mapping>
3.1.4 編寫測試類
-
在主配置文件中引入
User.hbm.xml
和Role.hbm.xml
<!-- 配置映射文件 --> <mapping resource="com/itzhouq/hibernate/domain/User.hbm.xml"/> <mapping resource="com/itzhouq/hibernate/domain/Role.hbm.xml"/>
-
測試類
package com.itzhouq.hibernate.demo2; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import com.itzhouq.hibernate.domain.Role; import com.itzhouq.hibernate.domain.User; import com.itzhouq.hibernate.utils.HibernateUtils; /** * Hibernate的多對多的映射 * @author itzhouq * */ public class Demo2 { @Test /* * 保存多條記錄:保存多個用戶和角色 */ public void test() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 1. 創(chuàng)建2個用戶 User user1 = new User(); user1.setUser_name("趙洪"); User user2 = new User(); user2.setUser_name("李兵"); // 2. 創(chuàng)建3個角色 Role role1 = new Role(); role1.setRole_name("研發(fā)部"); Role role2 = new Role(); role2.setRole_name("市場部"); Role role3 = new Role(); role3.setRole_name("公關(guān)部"); // 3. 設(shè)置雙向的關(guān)聯(lián)關(guān)系 user1.getRoles().add(role1); user1.getRoles().add(role2); user2.getRoles().add(role2); user2.getRoles().add(role3); role1.getUsers().add(user1); role2.getUsers().add(user1); role2.getUsers().add(user2); role3.getUsers().add(user2); // 4. 保存操作:多對多建立了雙向的關(guān)系必須有一方放棄外鍵維護(hù) // 5. 一般是被動方放棄外鍵維護(hù) 角色是被動方 恨课,需要在Role.hbm.xml文件中配置inverse=true // 比如舆乔,學(xué)生選課,課程是被選擇的庄呈,所以課程一方放棄外鍵維護(hù)蜕煌,需要在課程的映射文件中配置inverse=true session.save(user1); session.save(user2); session.save(role1); session.save(role2); session.save(role3); transaction.commit(); } }
-
Role.hbm.xml
文件中配置<!--inverse="true",Role一方放棄了外鍵的維護(hù)權(quán) --> <set name="users" table="sys_user_role" inverse="true"> <key column="role_id"/> <many-to-many class="com.itzhouq.hibernate.domain.User" column="user_id"/> </set>
3.2 Hibernate的多對多的操作
3.2.1 只保存一邊是否可以
@Test
/*
* 多對多的操作
* 只保存一邊是否可以?不可以诬留,瞬時態(tài)異常
*/
public void test2() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 1. 創(chuàng)建1個用戶
User user1 = new User();
user1.setUser_name("趙洪");
// 2. 創(chuàng)建1個角色
Role role1 = new Role();
role1.setRole_name("研發(fā)部");
// 3. 設(shè)置雙向的關(guān)聯(lián)關(guān)系
user1.getRoles().add(role1);
role1.getUsers().add(user1);
// 4. 保存用戶
session.save(user1);
transaction.commit();
}
3.2.2 級聯(lián)保存或更新
@Test
/*
* 多對多的操作
* 多對多的級聯(lián)保存:
* * 保存用戶級聯(lián)保存角色斜纪。主體是用戶。
* * 在User.hbm.xml中的set上配置cascade="save-update"
*/
public void test3() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 1. 創(chuàng)建1個用戶
User user1 = new User();
user1.setUser_name("李世民");
// 2. 創(chuàng)建1個角色
Role role1 = new Role();
role1.setRole_name("董事局");
// 3. 設(shè)置雙向的關(guān)聯(lián)關(guān)系
user1.getRoles().add(role1);
role1.getUsers().add(user1);
// 4. 保存用戶
session.save(user1);
transaction.commit();
}
3.2.3 級聯(lián)刪除【基本不用】
- 級聯(lián)刪除之前先查詢
3.2.4 其他操作
-
給用戶選擇角色
@Test /* * 給用戶選擇角色 */ public void test4() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 1. 給1號用戶多選3號角色 // 2. 查詢1號用戶 User user = session.get(User.class, 1L); // 3. 查詢3號角色 Role role = session.get(Role.class, 3L); // 4. 選擇角色 user.getRoles().add(role); transaction.commit(); }
- 注意修改前需要設(shè)置主配置文件的
<property name="hibernate.hbm2ddl.auto">update</property>
- 注意修改前需要設(shè)置主配置文件的
-
給用戶改選角色
@Test /* * 給用戶改選角色 */ public void test5() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 1. 將2號用戶原有的3號角色改為2號角色 // 2. 查詢2號用戶 User user = session.get(User.class, 2L); // 3. 查詢3號角色 Role role3 = session.get(Role.class, 3L); // 4. 查詢2號角色 Role role2 = session.get(Role.class, 2L); // 5. 改選角色 user.getRoles().remove(role3); user.getRoles().add(role2); transaction.commit(); }
-
給用戶刪除角色
@Test /* * 給用戶刪除角色 */ public void test6() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 1. 將2號用戶的1號角色刪除 // 2. 查詢2號用戶 User user = session.get(User.class, 2L); // 3. 查詢1號角色 Role role = session.get(Role.class, 1L); // 4. 刪除角色 user.getRoles().remove(role); transaction.commit(); }