[TOC]java
一對多
表之間關係
一對多sql
- 一個部門有多個員工,一個員工只能屬於某一個部門
- 一個班級有多個學生,一個學生只能屬於一個班級
多對多數據庫
- 一個老師教多個學生,一個學生能夠被多個老師教
- 一個學生能夠先擇多門課程,一門課程能夠被多個學生選擇
- 一個用戶能夠選擇多個角色,一個角色也能夠被多個用戶選擇
一對一session
- 一個公司只能對應一個註冊地址
表之間關係建表原則
一對多 在多的一方建立一個外鍵,指向一的一方的主鍵 多對多 建立一箇中間表,中間表至少有兩個字段,分別做爲外鍵指向多對多雙方的主鍵 一對一 惟一外鍵對應 主鍵對應app
一對多關係配置
創建表
建立表的 hbm.xml文件時,有外鍵可不建立列的映射dom
主表爲客戶(Customer),從表爲聯繫人(Linkman)ide
銷售聯繫人(linkman),一個聯繫人只能屬於某一個客戶 工具
CREATE TABLE `linkman` ( `link_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '聯繫人編號(主鍵)', `link_name` varchar(16) DEFAULT NULL COMMENT '聯繫人姓名', `link_cust_id` bigint(32) NOT NULL COMMENT '客戶id', `link_gender` char(1) DEFAULT NULL COMMENT '聯繫人性別', `link_phone` varchar(16) DEFAULT NULL COMMENT '聯繫人辦公電話', `link_mobile` varchar(16) DEFAULT NULL COMMENT '聯繫人手機', `link_email` varchar(64) DEFAULT NULL COMMENT '聯繫人郵箱', `link_qq` varchar(16) DEFAULT NULL COMMENT '聯繫人qq', `link_position` varchar(16) DEFAULT NULL COMMENT '聯繫人職位', `link_memo` varchar(512) DEFAULT NULL COMMENT '聯繫人備註', PRIMARY KEY (`link_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
客戶(customer),一個客戶能夠有多個聯繫人 測試
CREATE TABLE `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 '客戶所屬行業', `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;
關係圖
創建ORM
實體類與數據庫中創建字段 與 關係
Customer 實體類(一個客戶能夠有多個聯繫人)
package com.myxq.domain; import lombok.Getter; import lombok.Setter; import java.util.HashSet; import java.util.Set; @Getter@Setter 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; //創建一個客戶能夠有多個聯繫人 //放置多的一方的集合,hibernate默認使用的是Set集合 //若是使用List的話,它要對List進行排列,在表中要多建這一列,用來排序 //通常使用的都是Set集合 //如今是雙向關聯,從客戶能查聯繫人,從聯繫人也能查客戶 private Set<Linkman> linkmens = new HashSet<>(); @Override public String toString() { return "Customer{" + "cust_id=" + cust_id + ", cust_name='" + cust_name + '\'' + ", cust_source='" + cust_source + '\'' + ", cust_industry='" + cust_industry + '\'' + ", cust_level='" + cust_level + '\'' + ", cust_phone='" + cust_phone + '\'' + ", cust_mobile='" + cust_mobile + '\'' + '}'; } }
Linkman 實體類(一個聯繫人只能屬於一個客戶)
package com.myxq.domain; import lombok.Getter; import lombok.Setter; @Getter@Setter public class Linkman { private Long link_id; private String link_name; private String link_gender; private String link_phone; private String link_mobile; private String link_email; private String link_qq; private String link_position; private String link_memo; private String link_cust_id; //一個聯繫人只對應一個客戶 private Customer customer; @Override public String toString() { return "Linkman{" + "link_id=" + link_id + ", link_name='" + link_name + '\'' + ", link_gender='" + link_gender + '\'' + ", link_phone='" + link_phone + '\'' + ", link_mobile='" + link_mobile + '\'' + ", link_email='" + link_email + '\'' + ", link_qq='" + link_qq + '\'' + ", link_position='" + link_position + '\'' + ", link_memo='" + link_memo + '\'' + ", link_cust_id='" + link_cust_id + '\'' + ", customer=" + customer + '}'; } }
添加配置文件
1.客戶(Customer)實體類的配置文件fetch
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.myxq.domain.Customer" table="customer" > <!--創建類屬性哪個是主鍵 還要跟數據庫當中主鍵進行對象--> <id name="cust_id" column="cust_id" > <generator class="native"/> </id> <!--創建類中的普通屬性與數據庫當中的表字段的映射,關聯--> <property name="cust_name" column="cust_name" /> <property name="cust_source" column="cust_source"/> <property name="cust_industry" column="cust_industry"/> <property name="cust_level" column="cust_level"/> <property name="cust_phone" column="cust_phone"/> <property name="cust_mobile" column="cust_mobile"/> <!--一對多--> <set name="linkmens" cascade="save-update,delete" inverse="true"><!--set屬性名稱--> <key column="link_cust_id"></key><!--外鍵--> <one-to-many class="com.myxq.domain.Linkman"></one-to-many> </set> </class> </hibernate-mapping>
2.聯繫人(LinkMan)實體類配置文件 linkman.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.myxq.domain.Linkman" table="linkman" > <!--創建類屬性哪個是主鍵 還要跟數據庫當中主鍵進行對象--> <!-- 設置主鍵與OID的對應關係 --> <id name="link_id" column="link_id" > <generator class="native"/> </id> <!--創建類中的普通屬性與數據庫當中的表字段的映射 注意:外鍵不用設置--> <property name="link_name" column="link_name" /> <property name="link_gender" column="link_gender"/> <property name="link_phone" column="link_phone"/> <property name="link_mobile" column="link_mobile"/> <property name="link_email" column="link_email"/> <property name="link_qq" column=" link_qq"/> <property name="link_position" column=" link_position"/> <property name="link_memo" column=" link_memo"/> <!-- many-to-one:配置多對一 name:一的一方對象屬性名稱 class:一的一方類的全路徑 column:多的一方表的外鍵名稱 --> <many-to-one name="customer" cascade="save-update" class="com.myxq.domain.Customer" column="link_cust_id"/> </class> </hibernate-mapping>
在hibernate.cfg.xml中的<session-factory>標籤裏,添加核心配置文件
<!--加載映射文件--> <mapping resource="com/myxq/domain/customer.hbm.xml" /> <mapping resource="com/myxq/domain/linkman.hbm.xml" /> <mapping resource="com/myxq/domain/role.hbm.xml" /> <mapping resource="com/myxq/domain/user.hbm.xml" />
引入工具類
HibernateUtil.java
package com.myxq.utils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { public static final SessionFactory sessionFactory; static { //1.加載配置文件 Configuration configure = new Configuration().configure(); //configure.addResource("com/myxq/domain/Customer.hbm.xml"); //2.建立sessionFactory --JDBC 鏈接池 sessionFactory = configure.buildSessionFactory(); } public static Session openSession(){ Session session = sessionFactory.openSession(); return session; } public static Session getCurrentSession(){ Session session = sessionFactory.getCurrentSession(); return session; } }
編寫測試類
級聯操做
問題 在兩張表創建一對多關係時,若是隻保存一邊的對象,就會發異常 示例
什麼是級聯
在操做一個對象的時候,是否會操做其關聯的對象。
級聯分類
級聯保存或更新 級聯刪除
級聯是有方向性
在操做一的一方,是否會操做多的一方 操做多的一方時, 是否會操做一的一方
級聯保存或更新
級聯保存
操做的主體是誰,就要在誰的映射配置文件當中進行配置 在開始配置的set當中添加一個新的屬性cascade="save-update"
在多的一方添加級聯
再去運行,就不會報異常,兩條記錄都會被添加 在一的一方添加級聯
對象導航
兩方若是都加了級聯,這種咱們也稱爲雙向導航 設置雙向導航時,當對象存在關係時, 就會作出對應的操做
級聯更新
級聯刪除
刪除一邊數據時,同時將另外一邊的數據一併刪除
不設置級聯刪除
默認:先把外鍵改成空,而後再刪除
發送的SQL語句
設置級聯刪除
示例代碼
配置文件
在雙向級聯的過程中,會產生一些多餘的sql語句
緣由 當雙向維護時,兩都都維護了外鍵,當作更新操做時, 兩邊的外鍵都要去修改
解決辦法
1.使用單向維護 有些地方仍是會有問題 2.一方放棄維護權 在一的一方放棄外鍵維護權 在配置文件當中添加一個inverse="false/true" true爲放棄外鍵維護權,false爲不放棄外鍵維護權
cascade與inverse
cascade控制有沒有關聯對象 inverse控制有沒有外鍵 示例
lazy懶加載(默認值是proxy,不自動獲取外鍵對象)
改爲false,獲取外鍵對象
在linkman.hbm.xml
<many-to-one name="customer" class="com.myxq.domain.Customer" column="link_cust_id" lazy="false"/>
級聯保存或更新(解決 瞬時對象異常,只保存一邊)
在customer.hbm.xml
<set name="linkmens" cascade="save-update,delete" inverse="true"> <!--set屬性名稱--> <key column="link_cust_id"></key><!--外鍵--> <one-to-many class="com.myxq.domain.Linkman"> </one-to-many> </set>
多對多
多對多關係配置
創建表
用戶表,一個用戶能夠有多個角色
CREATE TABLE `user` ( `user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用戶id', `user_code` varchar(32) NOT NULL COMMENT '用戶帳號', `user_name` varchar(64) NOT NULL COMMENT '用戶名稱', `user_password` varchar(32) NOT NULL COMMENT '用戶密碼', `user_state` char(1) NOT NULL COMMENT '1:正常,0:暫停', PRIMARY KEY (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
角色表,一個角色能夠被多個用戶選擇
CREATE TABLE `role` ( `role_id` bigint(32) NOT NULL AUTO_INCREMENT, `role_name` varchar(32) NOT NULL COMMENT '角色名稱', `role_memo` varchar(128) DEFAULT NULL COMMENT '備註', PRIMARY KEY (`role_id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
關係圖
創建ORM
- 用戶
- 角色
Role.java
import lombok.Getter; import lombok.Setter; import java.util.HashSet; import java.util.Set; @Setter@Getter public class Role { private Long role_id; private String role_name; private String role_memo; //角色下面的全部用戶 private Set<User> users = new HashSet<>(); }
添加配置文件
用戶
角色
在覈心配置文件當中添加兩個新配置
編寫測試類
單向維護
雙向維護
雙向維護時,必需要有一方放棄外鍵維護 若是兩邊都有維護的話, 就會有重複的的記錄,因爲關係表是兩個字段做爲共同主鍵,不能有相同的記錄 解決辦法 一般都是讓被動方放棄,用戶選角色,角色爲被動方
多對多的級聯操做和一對多的級聯操做是同樣的
多對多的操做
關係的操做,只須要操做集合,就能夠操做它們之間的關係 給用戶添加一個新的角色
修改一個用戶的角色
刪除角色
查詢方式
OID查詢
什麼是OID查詢
- 根據對象的OID主鍵進行檢索
OID查詢方式
- get方法
- load方法
對象導航查詢
什麼是對象導航檢索
- Hibernate根據一個已經查詢到的對象,得到其關聯的對象的一種查詢方式
- 先查詢到聯繫人,就能夠經過聯繫人獲取聯繫人所關聯的客戶對象
有點像級聯查詢
HQL
什麼是HQL
- HQL查詢:Hibernate Query Language,Hibernate的查詢語言
- 是一種面向對象的方式的查詢語言,語法相似SQL。
- 經過session.createQuery(),用於接收一個HQL進行查詢方式。
- 注意:使用時,不能用*,對於表,要採用別名查詢
查詢
簡單查詢
別名查詢
排序查詢
條件查詢
位置綁定:根據參數的位置進行綁定條件
名稱綁定:把參數對應的值起一個名稱 再去設置名稱
投影查詢
查詢對象的某個或某些屬性 單個屬性
多個屬性
查詢多個屬性,封裝到對象當中 要在類中,提供構造方法
分頁查詢
統計查詢
查詢的結構只有一個
分組查詢
多表查詢
普通內鏈接
迫切內鏈接 經過hibernate將另外一個對象的數據,封裝該對象中
在普通內鏈接inner join 後添加一個關鍵字fetch
QBC
什麼是QBC
Query By Criteria,條件查詢。是一種更加面向對象化的查詢的方式。
查詢
簡單查詢
排序查詢
分頁查詢
條件查詢
條件 = eq > gt > = ge < lt <= le <> ne like in and or
單個條件
多個條件
統計查詢
離線條件查詢
- 脫離Session,添加條件
- 能夠在外部提早使用DetachedCriteria對象提交設置好條件
- 最後再綁定到session當中