Hibernate是什麼
面向java環境的對象/關係數據庫映射工具。
1.開源的持久層框架.
2.ORM(Object/Relational Mapping)映射工具,建立面向對象的域模型和關係數據模型之間的映射.
3.連接java應用和數據庫的中間件.
4.對JDBC進行封裝,負責java對象的持久化.
5.在分層結構中處於持久化層,封裝對數據庫的訪問細節,
使業務邏輯層更專注於實現業務邏輯
爲什麼要用Hibernate
1、Hibernate對JDBC訪問數據庫的代碼做了封裝,大大簡化
了數據訪問層繁瑣的重複性代碼。 ?2、Hibernate是一個基於jdbc的主流持久化框架,是一個優秀
的orm實現,它很大程度的簡化了dao層編碼工作。 ?3、Hibernate使用java的反射機制,而不是字節碼增強程序類實現
透明性 ?4、Hibernate的性能非常好,因爲它是一個輕量級框架。映射的靈
活性很出色。它支持很多關係型數據庫,從一對一到多對多的各
種複雜關係。
使用jdbc的問題:
1.操作數據相對繁瑣
2.數據庫字段發生變化時,對應sql語句都要發生變化,不利於後期維護
解決問題:封裝(hibernate)
配置文件(將javabean與數據庫表進行關聯) 放到與Customer類同級的目錄下,並且名稱一樣
Customer.hbm.xml
<hibernate-mapping>
<!--class:持久化類javabean與表的映射-->
<class name="cn.itcast.Customer" table="customer">
<!--id:用來映射主鍵ID-->
<id name="id" type="integer">
<column name="id"></column>
<!--gererator:主鍵生成策略-->
<gererator class="increment"/>
</id>
<!--type:表示hibernate的數據類型,用來關聯java的數據類型和數據庫的數據類型-->
<property name="name" column="name" type="string">
...
</class>
</hibernate-mapping>
配置文件(配置連接數據庫基本信息)
hibernate.cfg.xml
<hibernate-configration>
<sessionFactory>
<!--基本配置-->
<property name="hibernate.connection.driverClass">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf8</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--方言-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!--
自動將配置文件.hbm.xml的配置信息關聯數據庫表
create:表不存在時創建,存在時先刪再創建,然後添加數據
none:追加數據,不能創建表
update:表不存在時創建,存在時追加數據
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!--是否顯示sql語句-->
<property name="hibernate.show_sql">true</property>
<!--是否對sql語句格式化-->
<property name="hibernate.format_sql">true</property>
</sessionFactory>
</hibernate-configration>
加載配置文件:
Configuration configuration = new Configuration();
1.加載hibernate.cfg.xml
configuration.configure();//默認加載類路徑下文件
configuration.configure("cn/itcast/../hibernate.cfg.xml");
2.加載Customer.hbm.xml 要求配置文件和類放置到同一個目錄下,並且名稱一致
(1)configuration.addClass(Customer.class);
(2)configuration.addResource("cn/itcast/../Customer.hbm.xml");
(3)使用配置文件加載,在hibernate.cfg.xml中配置,項目中使用最多
<mapping resource="cn/itcast/../Customer.hbm.xml">
hibernate與jdbc對比:
hibernate:SessionFactory工廠(SessionFactory)、創建多個Session(Session)、使用Session來操作數據庫(CURD)
jdbc:連接池(DataSource)、多個連接(Connection)、使用Connection來操作數據庫(CURD)
hibernate基本配置:
1.使用hibernate更加面向對象(使用對象操作數據庫),對DAO層封裝,也就是對JDBC的封裝
2.建立工程
3.導入相應的jar包
4.建立一個持久化的javabean
5.建立Xxx.hbm.xml,用來映射持久化對象與數據庫表的對應關係,規範在hibernate核心包下org.hibernate.hibernate-mapping-3.0.dtd
6.建立連接數據庫信息的配置文件hibernate.cfg.xml,該文件放置到src目錄下,規範在hibernate核心包下org.hibernate.hibernate- configuration-3.0.dtd
7.測試操作數據庫的CURD
Hibernate的運行過程如下:
1、應用程序先調用Configuration類,該類讀取Hibernate配置文件及映射文件中的信息,
2、並用這些信息生成一個SessionFactory對象,
3、然後從SessionFactory對象生成一個Session對象,
4、並用Session對象生成Transaction對象;
A、可通過Session對象的get(),load(),save(),update(),delete()和saveOrUpdate()等方法對PO進行加載、保存、更新、刪除、等操作;
B、在查詢的情況下,可通過Session對象生成一個Query對象,然後利用Query對象執行查詢操作;如果沒有異常,Transaction對象將提交這些操作到數據庫中。
SessionFactory接口:SessionFactory負責維護Hibernate的二級緩存;SessionFactory是生成Session的工廠;是線程安全的
Session接口:Session是應用程序與數據庫之間交互操作的一個單線程對象,是 Hibernate 運作的中心,所有持久化對象必須在 session 的管理下纔可以進行持久化操作。此對象的生命週期很短。Session 對象有一個一級緩存,顯式執行 flush 之前,所有的持久層操作的數據都緩存在 session 對象處。相當於 JDBC 中的 Connection。是線程不安全的。
session的一級緩存:當使用get或者load方法通過OID進行查詢數據庫的時候,會將查詢結果放到session的一級緩存中,如果使用同一個OID再次查詢時,會先到session的一級緩存中查找是否有相同的OID對象,如果有則直接讀取,不再查詢數據庫;如果沒有則查詢數據庫,並將查詢結果放到session的一級緩存中。當session關閉時,一級緩存數據將不存在。
session快照
commit:先清理session的一級緩存,讓緩存中的數據與數據庫同步,然後再提交事務。
當使用get或者load方法通過OID進行查詢數據庫的時候,會將查詢結果放到session的一級緩存中,同時將數據產生(複製)一份快照,當修改session一級緩存中的數據時,並且執行commit()或者s.flush(),表示清理session的一級緩存,此時hibernate會使用OID查找快照中對應的OID對象的數據,然後比對,如果2個OID對象一樣,不會執行update語句,如果2個OID對象不一樣,會執行update語句。
主鍵生成策略(表示符生成器):
increment:由Hibernate以遞增的方式爲代理主鍵賦值
Hibernate會先讀取表中的主鍵的最大值,而接下來向表中插入記錄時, 就在 max(id) 的基礎上遞增,增量爲1(帶走加1:多線程有併發問題)
不依賴於底層數據庫系統,適合所有的數據庫系統;適用於只有單個Hibernate應用進程訪問同一個數據庫的場合;
OID必須爲long,int或short
identity:底層數據庫把主鍵定義爲自動增長字段類型(加1帶走:多線程沒有併發問題)
底層數據庫系統必須支持自動增長字段類型;OID 必須爲 long, int 或 short
native:依據底層數據庫對自動生成標識符的支持能力, 來選擇使用 identity, sequence 或 hilo 標識符生成器
適合於跨數據庫平臺開發;
OID 必須爲 long, int 或 short
複合主鍵
1.<composite-id>
<key-property name="" column="" type=""/>
<key-property name="" column="" type=""/>
</composite-id>
2.將複合主鍵單獨創建一個類,在持久化類中用一個屬性表示
<composite-id name="" class="">
uuid:Hibernate會產生不重複的32位字符串作爲主鍵
關聯關係
<many-to-one name="外鍵屬性名" class="外鍵屬性對應類路徑" cascade="save-update">
<column name="表中外鍵名"></column>
</many-to-one>
自動持久化所關聯對象
cascade="save-update",表示級聯保存和更新,當保存或更新對象時,此時會級聯保存或更新和此對象相關聯的其他對象,也就是將對象持久化
<set name="持久化類中集合的屬性名稱" table="集合屬性映射的多的一端外鍵表名稱" cascade="save-update">
<key>
<column name="外鍵列的名稱"></column>
</key>
<one-to-many class="一對多集合中對應的類型全路徑"/>
</set>
Hibernate要求在持久化類中定義集合屬性時,必須把屬性聲明爲接口類型;創建集合0表示初始集合的同時初始化集合的長度,避免空指針異常
對象導航:在兩端都配置cascade="save-update",保存一個對象,與之相關聯的對象也會保存
inverse:在hibernate中通過對inverse屬性的值決定是由雙向關聯的哪一方來維護表和表之間的關係.inverse=false 的爲主動,inverse=true 的爲被動方, 由主動方負責維護關聯關係。在沒有設置 inverse=true 的情況下,父子兩邊都維護父子關係。
在 1-n 關係中,將 n 方設爲主控方將有助於性能改善。
建立兩個對象的關聯關係:
customer.getOrders().add(order);
order.setCustomer(customer);同時修改關聯兩端的相應屬性會使程序更加健壯,提高業務邏輯層的獨立性,使業務邏輯層的程序代碼
不受Hibernate實現類的影響。
解除兩個對象的關聯關係:
Customer.getOrders().remove(order);
Order.setCustomer(null);
級聯刪除:cascade="delete" 當刪除對象的同時,級聯刪除和對象表相關的外鍵表中的數據。
自動刪除解除了關聯關係的對象(刪除孤兒):cascade="delete-orphan" 或 cascade="all-delete-orphan"(包含所有行爲)
在數據庫中對集合排序:<set order-by="id desc/asc">
操縱持久化對象
session.flush();清理session的一級緩存,讓緩存中的數據與數據庫同步,從而進行CRUD操作,方向:緩存--->數據庫,緩存中的數據不丟失
tx.commit():先調用session.flush()清理session的一級緩存,讓緩存中的數據與數據庫同步,然後再提交事務
session.clear();清空緩存,將一級緩存中的數據清空
session.refresh();重新刷新緩存區域,使緩存中的數據與數據庫同步,方向:數據庫--->緩存,使用對象的OID再查詢一遍數據庫
緩存清理模式:
session.setFlushMode(FlushMode.NEVER);//永不清理緩存
s.flush();此時可以清理session緩存
commit();此時不調用flush()
hibernate中java對象的狀態:
持久化狀態(託管):OID 不爲 null
;位於 Session 緩存中
;持久化對象和數據庫中的相關記錄對應;如果從臨時對象轉變而來,此時在數據庫中不存在對應記錄;Session 在清理緩存時, 會根據持久化對象的屬性變化, 來同步更新數據庫;
在同一個 Session 實例的緩存中, 數據庫表中的每條記錄只對應唯一的持久化對象
臨時狀態:OID 通常爲 null
;不處於 Session 的緩存中
;在數據庫中沒有對應的記錄
遊離狀態(脫管):OID 不爲 null
;不再處於 Session 的緩存中;
一般情況需下, 遊離對象是由持久化對象轉變過來的, 因此在數據庫中可能還存在與它對應的記錄。
刪除狀態:OID 不爲 null
;從一個 Session實例的緩存中刪除
;Session 已經計劃將其從數據庫刪除, Session 在清理緩存時, 會執行 SQL delete 語句, 刪除數據庫中的對應記錄。
evict():持久化狀態--->遊離狀態
update():遊離狀態--->持久化狀態
unsave-value:用來判斷當前對象是臨時對象還是持久對象,默認值是0
get() load()
1.相同點:都可以根據給定的OID從數據庫中加載一個持久化對象
2.不同點:當數據庫中不存在與 OID 對應的記錄時, load() 方法拋出 ObjectNotFoundException 異常, 而 get() 方法返回 null
2013.7.12
組件:一個類(Address)不能單獨映射一個表,它的存在依賴於另一個主體類(Customer)
Customer.hbm.xml
<component name="持久化對象類中的屬性" class="該屬性的對應數據類型(全路徑)">
<parent name="customer"/>//表示是屬於整體類的一部分(可加可不加)
<property name="組件中的屬性名" column="映射數據表的列" type="hibernate的數據類型"/>
</component>
持久化類的屬性分爲兩種:
值(value)類型: 沒有 OID, 不能被單獨持久化, 生命週期依賴於所屬的持久化類的對象的生命週期,組件類型就是一種值類型
實體(entity)類型: 有 OID, 可以被單獨持久化, 有獨立的生命週期
映射多對多的關聯關係:使用set集合
中間表:將多對多的關係分成兩個一對多的關係
多對多的關聯關係修改中間表的時候,不是執行update,而是先刪除再插入
若管理關聯關係的一方(主控方)刪除該表數據時,先刪除中間表與另一表相關聯的數據,然後再刪除該表數據
hibernate的檢索策略:
立即檢索:立即加載檢索方法指定的對象,lazy="false"。
*會使用OID立即查詢數據庫,獲取該對象所有的的屬性。
延遲檢索:延遲加載檢索方法指定的對象,lazy="true"。
*當使用load方法通過OID進行查詢的時候,會生成一個代理對象,代理對象只初始化OID,查其他屬性時才查詢數據庫,顯示sql語句,獲取相應的其他屬性的值。
迫切左外連接檢索(fetch屬性值設爲“join”):通過左外連接加載與檢索指定的對象關聯的對象。
<class lazy="true">//說明當前類默認是延遲檢索
get方法使用OID進行查詢時,永遠是立即檢索
只有使用load方法才能夠測試出立即檢索和延遲檢索
判斷當前對象是延遲檢索還是立即檢索,判斷當前對象是否對值進行初始化: Hibernate.isInitialized(c)
對其進行初始化:
方法一:只要調用除OID之外的其他屬性,此時可以對代理對象進行初始化.
方法二:將代理對象進行初始化,查詢數據庫,對數據進行初始化: Hibernate.initialize(c);
類級別的檢索:session的方法直接檢索Customer對象,對Customer對象到底採用立即檢索
還是延遲檢索方式
通過class元素的lazy屬性設定。
關聯級別的檢索:通過set元素lazy屬性設定。
關聯級別set中
* lazy = true(默認值):延遲檢索,延遲加載只要調用關聯的訂單對象時才查詢數據庫
* lazy = false:立即檢索,只要初始化客戶對象,和它關聯的集合對象也馬上被初始化(馬上查詢數據庫)
一對多和多對多關聯的檢索策略(set): <set> 元素的 lazy 和 fetch 屬性:
fetch lazy
-------------------------------------
join false 採用迫切左外聯接檢索。
join true 採用迫切左外聯接檢索。
join extra 採用迫切左外聯接檢索。
select false 採用立即檢索
select true 採用延遲檢索
select extra 採用延遲檢索(極其懶惰:只查需要的)
subselect false 採用立即檢索(嵌套子查詢)
subselect true 採用延遲檢索(嵌套子查詢)
subselect extra 採用延遲檢索(極其懶惰)(嵌套子查詢)
迫切左外連接檢索(fetch 屬性值設爲 “join”)
Query 的list() 方法會忽略映射文件中配置的迫切左外連接檢索策略,而依舊採用立即檢索還是延遲加載策略由set集合的lazy屬性決定。
組合1 many2one立即檢索+set立即檢索
<many-to-one name="customer" class="cn.itcast.l_query.Customer" fetch="select" lazy="false">
<set name="orders" table="l_order" inverse="true" fetch="select" lazy="false">
組合2 many2one迫切左外+set立即檢索
<many-to-one name="customer" class="cn.itcast.l_query.Customer" fetch="join" lazy="false">
<set name="orders" table="l_order" inverse="true" fetch="select" lazy="false">
組合3 many2one立即檢索+set迫切左外
<many-to-one name="customer" class="cn.itcast.l_query.Customer" fetch="select" lazy="false">
<set name="orders" table="l_order" inverse="true" fetch="join" lazy="false">
批量檢索 從一的一端查詢 查詢所有的客戶:<set> 元素有一個batch-size 屬性,用來爲延遲檢索策略或立即檢索策略設定批量檢索的數量. 批量檢索能減少 SELECT 語句的數目, 提高延遲檢索或立即檢索的運行性能. 默認值是1。
注:query.list()屬於hql檢索,hql檢索忽略關聯級別的迫切左外連接檢索,只與lazy屬性有關.
當在<set>元素中定義batch-size=3(使用嵌套子查詢合併sql語句)
批量檢索 從多的一端查詢 查詢所有的訂單:在Customer.hbm.xml文件中增加batch-size屬性
當在Customer.hbm.xml的<class>元素中定義batch-size=3(使用嵌套子查詢合併sql語句)