Hibernate
- hibernate架構
- hibernate實體規則
-
- 實體内建立的注意事項
- 主鍵類型
- 主鍵生成政策generator
- hibernate中的對象狀态
-
- hibernate進階
- hibernate中的事務
- hibernate中的批量查詢
- hibernate多表操作
- hibernate的多表查詢
hibernate架構
1.什麼是架構
提高我們的開發效率.可以了解成是一個半成品項目.
2.hibernate架構
dao層架構
操作資料庫.
以面向對象的方式操作資料庫.
orm 思想. 對象關系映射. 通過映射檔案配置對象與資料庫中表的關系
O 對象
R 關系型資料庫
M 映射檔案
3.hibernate架構搭建
-
導包
required+驅動包
- 準備實體類 以及 orm中繼資料
- 建立主配置檔案
- 書寫代碼測試
4.配置檔案詳解
- orm中繼資料(xxx.hbm.xml)
<hibernate-mapping package="">
<class name table>
<id name >
<generator class="">
</id>
<property name="" />
- hibernate.cfg.xml
-
必選配置
4+1 方言
-
<!-- 資料庫驅動 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 資料庫url -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate_32</property>
<!-- 資料庫連接配接使用者名 -->
<property name="hibernate.connection.username">root</property>
<!-- 資料庫連接配接密碼 -->
<property name="hibernate.connection.password">1234</property>
<!-- 資料庫方言
不同的資料庫中,sql文法略有差別. 指定方言可以讓hibernate架構在生成sql語句時.
針對資料庫的方言生成.
sql99标準: DDL 定義語言 庫表的增删改查
DCL 控制語言 事務 權限
DML 操縱語言 增删改查
注意: MYSQL在選擇方言時,請選擇最短的方言.
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
-
可選配置
顯示sql
格式化sql
自動生成表
<!-- 将hibernate生成的sql語句列印到控制台 -->
<property name="hibernate.show_sql">true</property>
<!-- 将hibernate生成的sql語句格式化(文法縮進) -->
<property name="hibernate.format_sql">true</property>
<!--
## auto schema export 自動導出表結構. 自動建表
#hibernate.hbm2ddl.auto create
自動建表.每次架構運作都會建立新的表.以前表将會被覆寫,表資料會丢失.(開發環境中測試使用)
#hibernate.hbm2ddl.auto create-drop
自動建表.每次架構運作結束都會将所有表删除.(開發環境中測試使用)
#hibernate.hbm2ddl.auto update(推薦使用)
自動生成表.如果已經存在不會再生成.如果表有變動.自動更新表(不會删除任何資料).
#hibernate.hbm2ddl.auto validate
校驗.不自動生成表.每次啟動會校驗資料庫中表是否正确.校驗失敗.
-->
<property name="hibernate.hbm2ddl.auto">update</property>
- 指定隔離級别和orm中繼資料引入
<!-- 指定hibernate操作資料庫時的隔離級别
#hibernate.connection.isolation 1|2|4|8
0001 1 讀未送出
0010 2 讀已送出
0100 4 可重複讀
1000 8 串行化
-->
<property name="hibernate.connection.isolation">4</property>
<!-- 指定session與目前線程綁定 -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 引入orm中繼資料
路徑書寫: 填寫src下的路徑
-->
<mapping resource="com/dustdawn/entity/Customer.hbm.xml" />
5.api詳解
Configuration 讀取配置
sessionFactory 建立session
Session 獲得事務操作對象,以及資料增删改查
Transaction 控制事務
hibernate實體規則
實體内建立的注意事項
- 持久化類提供無參數構造
- 成員變量私有,提供共有get/set方法通路,需提供屬性
- 持久化類中的屬性,因盡量使用包裝類型(不會錯,且值能為null)
- 持久化類需要提供oid,與資料庫中的主鍵列對應
- 不要用final修飾class(非接口代理,hibernate使用cglib代理生成代理對象,代理對象是繼承被代理對象,如果被final修飾将無法生成代理)
主鍵類型
-
自然主鍵
表的業務列中,有某業務列符合,必須有,并且不重複的特征時,該列可以作為主鍵使用
-
代理主鍵
表的業務列中,沒有某業務列符合,必須有,并且不重複的特征時,建立一個沒有業務意義的列作為主鍵
主鍵生成政策generator
就是每條記錄錄入時,主鍵的生成規則(7個)
xxx.hbm.xml
< id name=“cust_id” >
< generator class=“native”>< /generator>
< /id>
- 代理主鍵
- identity : 主鍵自增.由資料庫來維護主鍵值.錄入時不需要指定主鍵.
- sequence: Oracle中的主鍵生成政策.
- increment(了解): 主鍵自增.由hibernate來維護.每次插入前會先查詢表中id最大值.+1作為新主鍵值.
- hilo(了解): 高低位算法.主鍵自增.由hibernate來維護.開發時不使用.
- native:hilo+sequence+identity 自動三選一政策.
- uuid: 産生随機字元串作為主鍵. 主鍵類型必須為string 類型.
- identity : 主鍵自增.由資料庫來維護主鍵值.錄入時不需要指定主鍵.
- 自然主鍵
- assigned:自然主鍵生成政策. hibernate不會管理主鍵值.由開發人員自己錄入.
hibernate中的對象狀态
Session接口是hibernate應用程式提供的操作資料庫的接口,提供了基本的儲存,更新,删除,和加載java對象的方法。Session具有一個緩沖,位于緩存中的對象稱為持久化對象。
- 瞬時狀态
- 沒有id,沒有與session關聯(沒有在session緩存中):customer.setCust_name("");
- 持久化狀态
- 有id,與session關聯(在session緩存中):session.save(customer);
- 特點:持久化狀态對象的任何變化自動同步到資料庫中
- 遊離/托管狀态
-
有id,沒有與session關聯(沒有在session緩存中):session.close();
Customer c1 = new Customer();
c1.setCust_id(1l);
設定id不存在對應瞬時,存在則遊離
-
session的save()方法不能了解成儲存,應該了解成将瞬時狀态轉換成持久狀态的方法。
主鍵自增,執行save方法,為了将對象轉換成持久化狀态,必須生成id值,是以需要執行insert語句生成
saveOrUpdate方法将任意對象将對象轉換成持久化對象
==持久化狀态的對象,會在事務送出是,自動同步到資料庫中
hibernate使用原則:将我們希望同步到資料庫的資料,對應的對象轉換成持久化狀态
hibernate進階
一級緩存
- 緩存:提高效率,hibernate中的一級緩存是為了提高操作資料庫的效率
-
一級緩存:為了提高效率,session對象中有一個可以存放對象的集合
查詢時:第一次查詢時,會将對象放入緩存,再次查詢時,會傳回緩存中的,不再查詢資料庫
修改時:會使用快照對比修改前和修改後對象的屬性差別,隻執行一次修改
- 提高效率手段1:提高查詢效率
- 提高效率手段2:減少不必要的的修改語句發送(快照)
持久化狀态對象其實就是放入session緩存中的對象
hibernate中的事務
Service層
HibernateUtils.getCurrentSession().beginTransaction();
操作事務
HibernateUtils.getCurrentSession().getTransaction().commit();
HibernateUtils.getCurrentSession().getTransaction().rollback();
Dao層
Session session = HibernateUtils.getCurrentSession();
session.get();
- 事務特性
-
A — 原子性
事務可以看做資料庫操作的容器,對事務所包裹的操作被認為像實體上的原子,是最小、不可分割的機關,要麼全成功,要麼全失敗
-
C — 一緻性
事務在送出前後資料總量不應該發生變化(賴以保證的基礎是原子性)
-
I — 隔離性
多個事務在并發産生的時候,可能會産生一些負面問題(髒讀、不可重複讀、幻讀)
提供隔離級别解決
-
D — 持久性
保證事務送出之後,涉及到操作的資料必須被寫入持久化媒體(如硬碟)中
-
- 事務并發問題
-
髒讀
某事務讀到了另一個事務正在操作但未送出的資料
-
不可重複讀
一次事務中兩次連續的讀取到的資料内容不一緻(過程中其他事務修改資料并送出了)
-
幻/虛讀
一次事務中兩次連續的讀取到的資料數量不一緻(過程中其他事務增加資料并送出了)
-
解決方法:
-
事務的隔離級别
1)read uncommitted : 讀取尚未送出的資料 :哪個問題都不能解決
2)read committed:讀取已經送出的資料 :可以解決髒讀 ---- oracle預設的
3)repeatable read:重讀讀取:可以解決髒讀 和 不可重複讀 —mysql預設的
4)serializable:串行化:可以解決 髒讀 不可重複讀 和 虛讀—相當于鎖表操作資料隻允許串行,不允許并發
知識點1. 在Hibernate中配置操作資料庫中的隔離級别
<!-- 指定hibernate操作資料庫時的隔離級别
#hibernate.connection.isolation 1|2|4|8
0001 1 讀未送出
0010 2 讀已送出
0100 4 可重複讀
1000 8 串行化
-->
<property name="hibernate.connection.isolation">4</property>
知識點2. 在項目中如何管理事務
- 在業務開始之前打開事務
- 業務執行之後送出事務
- 執行過程中出現異常復原事務
-
在dao層操作資料庫需要用到session對象,在service層控制事務也是使用session對象完成,要保證dao層和service層使用同一個session
解決方法
原理:将session對象綁定到ThreadLocal線程
調用sessionfactory.getCurrentSession()方法即可獲得與目前線程綁定的session對象
方法:hibernate.cfg.xml中配置
<!-- 指定session與目前線程綁定 -->
<property name="hibernate.current_session_context_class">thread</property>
注意1:調用getCurrentSession方法必須配合主配置中的上配置
注意2:通過getCurrentSession方法獲得的session對象,當事務送出時,session會自動關閉,不要手動調用close關閉
hibernate中的批量查詢
-
HQL查詢(多表查詢,但不複雜時使用)
Hibernate Query Language(Hibernate獨家查詢語言,屬于面向對象的查詢語言)
HQL語句中,不可能出現任何資料庫相關的資訊的
- 基本查詢
- 條件查詢
- 分頁查詢
-
Criteria查詢(單表查詢)
Hibernate自創的無語句面向對象查詢
- 基本查詢
- 條件查詢
- 分頁查詢
- 查詢總記錄數
- 原生SQL查詢(複雜的業務查詢)
- 基本查詢
- 條件查詢
- 分頁查詢
hibernate多表操作
- 多對一/一對多
-
關系表達
表中的表達:外鍵指向一的一方主鍵
在對象中的表達:使用集合表達,一的一方持有多個多的一方
使用對象引用一的一方,表達多的一方屬于哪個一的一方
- 操作
<set name="linkMens" cascade="save-update" inverse="true"> <!--外鍵列名 --> <key column="lkm_cust_id"></key> <one-to-many class="LinkMan" /> </set> <many-to-one name="customer" column="lkm_cust_id" class="Customer" > </many-to-one>
- 級聯操作
-
關系維護
在儲存時,兩方都會維護外鍵關系,關系維護兩次造成備援,多餘的維護關系語句顯然是客戶這一端在維護關系(聯系人一端通過外鍵已經維護關系)
多的一方(LinkMan)不能放棄維護關系,因為外鍵字段就在多的一方
原則:無論怎麼放棄,總有一方必須要維護關系
一對多關系中:隻能一的一方放棄維護,多的一方不能放棄維護
( 如果客戶放棄維護與聯系人的關系. 維護關系的代碼可以省略
如果執行删除主表操作時,主表選擇維護關系,可以解除與從表的外鍵限制,從表外鍵置空,記錄不變,級聯操作為delete時,會将兩表一同删除)
-
- 多對多
-
關系表達
使用中間表,至少兩列,都是外鍵列,分别引用兩張表的主鍵
兩方都使用集合來表達擁有多個對方
-
操作
orm中繼資料xxx.hbm.xml
将來在開發中,如果遇到多對多關系.一定要選擇一方放棄維護關系.
一般誰來放棄要看業務方向. 例如錄入員工時,需要為員工指定所屬角色.
那麼業務方向就是由員工維護角色. 角色不需要維護與員工關系.角色放棄維護
- 級聯操作
-
hibernate的多表查詢
- 查詢總結
-
oid查詢—get方法
session.get(實體類.class,id)
- 對象屬性導航查詢
- HQL
- 基礎文法
- 排序
- 條件
- 分頁
- 聚合
- 投影
-
多表查詢
内連接配接(迫切fetch封裝成一個對象) inner join(fetch)
外連接配接
- 左外(迫切) left join(fetch)
- 右外(迫切)right join(fetch)
- Criteria
- 基本文法
- 離線查詢
- 原生SQL
-
- 查詢優化
-
類級别查詢
session.get()方法:沒有任何政策,調用即立即查詢資料庫加載資料
session.load()方法(true:預設延遲加載):是在執行時,不發送任何sql語句,傳回一個對象,使用該對象時,才執行查詢(orm中繼資料檔案中class元素上配置lazy屬性來控制:
< class name=“Customer” table=“cst_customer” lazy=“true”>)
結論:為了提高效率.建議使用延遲加載(懶加載),優化查詢延遲加載:僅僅獲得沒有使用,不會查詢,在使用時才進行查詢 lazy(預設值):true,查詢類時,會傳回代理對象(帶$符号)不去查詢,而在使用屬性時,調用代理對象增強的方法,根據關聯的session查詢資料庫加載資料
-
關聯級别查詢
set元素中配置
對象屬性導航:Customer的屬性getLinkMen導航另一個對象
- 集合政策(一的一方Customer,取LinkMan)
-
延遲加載&抓取政策
extra:如果隻獲得集合的size,隻查詢集合的size(count語句),不會列印資料
fetch為join時,類級别加載lazy屬性失效
-
- 關聯屬性政策(多的一方LInkMan,加載Customer) 結論:為了提高效率.fetch的選擇上應選擇select, lazy的取值應選擇 true. 全部使用預設值.
-
no-session問題解決
采用上結論懶加載時,傳回頁面是為代理對象,到達頁面時service層執行完畢,session關閉,會出現懶加載初始化缺少session對象的情況
- 集合政策(一的一方Customer,取LinkMan)
-
批量抓取
周遊每個客戶都要用sql語句查詢聯系人
-