1、 left outer join 左外連接:
左外連接的查詢結果集中包括指定左表(主表)中的所有行,
* 而不僅僅是連接列的所有行。如果左表的某行在右表(從表)中沒有找到匹配的行,則結果
???? ? * 集中的右表的相對的位置為 NULL
2、關于hibernate.hbm2ddl.auto
? <property name="hibernate.hbm2ddl.auto">update</property>
???? 將這個屬性設為 update 只有我們發生修改的時候才會重新創建表 否則不會被覆蓋掉(未理解)
,在SessionFactory創建時,自動檢查數據庫結構,或者將數據庫schema的DDL導出到數據庫。使用
create-drop時,在顯式關閉SessionFactory時,將drop掉數據庫schema.
??????? 例如:我們將所有的表都刪除了當我們執行插入操作時,SessionFactory被創建那么會自動檢
查數據庫scheme的DDL,建立數據表,并且會保留原來的數據,所以我們不用 Export 配置中的數據到數
據庫,那樣會覆蓋掉所有的數據。
3、?關于對象關系信息導出
這里必須調用 configure 方法 否則會映射 properties 文件
??????? Configuration cfg = new Configuration().configure();??
??//用于導出用戶定義的 xml 配置信息,在數據庫中生成對應的Table
??SchemaExport export = new SchemaExport(cfg);
??export.create(true, true);
4、* 測試lazy在class上的策略 這里默認為true
我們在這里應當搞清session.get()和session.load()的區別
方法load支持 lazy(在Session緩存中生成一個User的子類對象返回,只有當調用方法是才查詢) 如果
不存在查詢的結果則拋異常
? ???session = HibernateUtil.getSession();
???tx = session.beginTransaction();
??????????? Classes c1 = (Classes)session.load(Classes.class, 1);
??????????? System.out.println("c1.getId()"+c1.getId());
??????????? System.out.println("c1.getName()"+c1.getName());
這里不會發出sql語句,因為這里就采用lazy策略,所以這里采用了第三方的組件返回了一個,一個新的
Classes 的實例(代理),只有當我們需要查詢屬性時才會發出算sql語句,在這里不會發出sql語句因為
id 是我們輸入的。
hibernate 支持的lazy 策略只在session的生命周期內有效。
5、lazy在collection上的策略
?很顯然這些lazy都是默認的
????Classes c1 = (Classes)session.load(Classes.class, 1);
???//如果我們將集合上的lazy設為false,這里會發出兩條sql除了將要查詢的
普通屬性查出來外,還會將非普通屬性
???//將集合上的lazy設為extra和true是一樣的
???System.out.println("c1.name= " + c1.getName());
???//沒有發出sql 但是會生成一個 persistent 的set作為代理
??????????? Set students = c1.getStudents();
??????????? for(Iterator it = students.iterator();it.hasNext();){
??????????? ?Student s = (Student)it.next();
??????????? ?System.out.println("student.name= " + s.getName());
??????????? }
??????????? //System.out.println("student.number= " + student.size());
??????????? //這里會將所有的數據讀取出來并生成對象存放在set中
??????????? /*這里Classes的lazy策略只對普通的屬性有關,而collection的lazy策略才對
???????????? * collection對象生效*/
*測試在標簽上的lazy 策略和集合上的lazy策略一樣。
6、one2one
<class name="org.n2535.hibernate.Person" table="t_person">
? <id name="id">
? <!-- 這里表示了Person的主鍵是作為一個外鍵關聯了IdCard的主鍵 -->
???? <generator class="foreign">
???? <!-- 表示主鍵的生成是根據 屬性 idCard 的 id -->
?????? <param name="property">idCard</param>
???? </generator>
? </id>
? <property name="name" />
? <!-- 表示了Person與Idcard是一對一的關系 默認為根據主鍵加載對象(主鍵關聯) -->
??????? <!-- constrained(約束) (可選) 表明該類對應的表對應的數據庫表,
?????????????? 和被關聯的對象所對應的數據庫表之間,通過一個外鍵引用對主鍵進行約束。
????????????? 而且它們之間的約束條件為true
??????? 在這里默認了兩者的級聯操作,否則的話一方的主鍵就為空沒有任何意義了 -->
? <one-to-one name="idCard" constrained="true"/>
</class>
關于idCard的xml配置可以用
?? <!-- 默認為主鍵關聯 即加載cardNo 時根據其主鍵將 關聯的Person表中 主鍵相同的 元組
取出
?????? 默認的抓取策略為 Join? -->
? <one-to-one name="person"/>
當然也可以不用。
7、extends
?<!-- 測試每個具體的類映射一種表,這里Animal應該是抽象的,所以不應該被生成出來,將
abstract="true"-->
<class name="Animal" abstract="true">
? <id name="id">
???? <generator class="assigned"/>
? </id>
? <!-- 此處不需要鑒別器,因為每個具體的類都生產了一張表 -->
? <property name="name" />
? <property name="sex" />
? <union-subclass name="Pig" table="t_pig">
? <property name="weight"/>
? </union-subclass>
?
? <union-subclass name="Bird" table="t_bird">
? <property name="height"/>
? </union-subclass>
?</class>?
<!-- 測試單表繼承映射 -->
<class name="Animal" table="t_animal" lazy="false">
? <id name="id">
???? <generator class="native"/>
? </id>
? <!-- discriminator 鑒別器,用來識別不同的子類 -->
? <discriminator column="type" type="string"/>
?
? <property name="name" />
? <property name="sex" />
? <!-- Pig -->
? <!-- discriminator-value的默認是完整的類名 -->
? <subclass name="Pig" discriminator-value="P">
??? <property name="weight"/>
? </subclass>
?
? <!-- Bird -->
? <subclass name="Bird" discriminator-value="B">
??? <property name="height"/>
? </subclass>
?</class>
8、component 組件映射測試
?component類不是一個實體類,在hibernate中的實體是指的 一個Pojo+一個映射文件
??component類是一個輔助類
?? component 組件映射
? <component name="contact" class="org.n2535.hibernate.Contact">
??? <property name="email"/>
??? <property name="address"/>
??? <property name="zipCode"/>
??? <property name="contactTel"/>
? </component>
9、復合主鍵
因為主鍵是不可重復的,所以在復合主鍵的類中我們實現了Serializable接口,
和hashcode、equals方法,能夠確保主鍵的唯一性。
?<!-- 復合主鍵映射我們也可以認為是一種 component 組件映射的一種? -->
?? <composite-id name="pk">
?? <key-property name="productYear"/>
?? <key-property name="productMonth"/>
?? </composite-id>
?? <property name="name"/>
?? <property name="factory"/>
?</class>?
10、集合映射
??
? <set name="setValue" table="t_set_value">
? ?<key column="set_id"/>
? ?<element type="string" column="set_value"/>
? </set>
?
? <list name="listValue" table="t_list_value">
? ?<key column="list_id"/>
? ?<!-- 這里必須給出排序的索引,因為list是有序的(下同) -->
? ?<list-index column="list_index"/>
? ?<element type="string" column="list_value"/>
? </list>
?
? <array name="arrayValue" table="t_array_value">
? ?<key column="array_id"/>
? ?<list-index column="array_index"/>
? ?<element type="string" column="array_value"/>
? </array>
?
? <map name="mapValue" table="t_map_value">
? ?<key column="map_id"/>
? ?<map-key type="string" column="map_key"/>
? ?<element type="string" column="map_value"/>
? </map>
11、關于Hibernate的鎖
?1)、悲觀鎖:先獲得數據庫的鎖的線程,知道該線程放棄提交,其他的線程將無法修改該數據
(LockMode.UPGRADE :利用數據庫的for update子句加鎖。)
2)、樂觀鎖:通常利用一個 version 的版本沖突來實現,實際上不是數據庫的鎖,一個線程的version
必須大于數據庫中的version值才能被存儲,否則報錯。這樣提供了比悲觀鎖寬松的條件,只要 version
大于數據庫中的version就可以被存儲,而不會因為是否死一個線程先獲得鎖,因為樂觀鎖根本就不是一
種鎖。
? * 未使用悲觀鎖的時候,不同的操作可以訪問相同的數據,那么會造成數據的錯誤
? * 使用悲觀鎖的時候,可以避免這個問題
可以不用顯示的調用,如果為調用update那么在提交的時候會自動的update,當第一個操作將數據鎖住
的時候,(所有的其他訪問將被禁止)第二個select操作將會阻塞,知道第一個操作釋放了鎖,第二個
對象的選擇操作會根據第一個對像的update的結果來讀取數據,如果兩個對象都從數據庫中讀取了相同
的數據,那么第一次的update操作,將會被第二次的覆蓋,造成錯誤的數據。
?session.update(inv);
?要使用悲觀鎖請使用指定的數據庫的命令,或者使用hibernate中的配置。
? * 樂觀鎖采用的version的沖突機制,如果update的version小于或數據庫中的version
? * 將會產生錯誤插入失敗,一位update的限制條件是根據 主鍵和version 所以會失敗
? * 我們還能仿照 Hibernate 的樂觀鎖機制,用Jdbc實現樂觀鎖
?
12、hibernate查詢語言hql?
在hql中關鍵字不區分大小寫,但是屬性和類名區分大小寫
1)、簡單屬性查詢【重要】
?* 單一屬性查詢,返回結果集屬性列表,元素類型和實體類中相應的屬性類型一致
?* 多個屬性查詢,返回的集合元素是對象數組,數組元素的類型和對應的屬性在實體類中的類型
一致
?? 數組的長度取決與select中屬性的個數
?* 如果認為返回數組不夠對象化,可以采用hql動態實例化Student對象
?參見:SimplePropertyQueryTest.java?
2)、實體對象查詢【重要】
?* N + 1問題,在默認情況下,使用query.iterate查詢,有可以能出現N+1問題
?? 所謂的N+1是在查詢的時候發出了N+1條sql語句
?? 1: 首先發出一條查詢對象id列表的sql
?? N: 根據id列表到緩存中查詢,如果緩存中不存在與之匹配的數據,那么會根據id發出相應的
sql語句
?* list和iterate的區別?
??* list每次都會發出sql語句,list會向緩存中放入數據,而不利用緩存中的數據
??* iterate:在默認情況下iterate利用緩存數據,但如果緩存中不存在數據有可以能
出現N+1問題
?參見:SimpleObjectQueryTest1.java/SimpleObjectQueryTest2.java
?
3)、條件查詢【重要】?
?* 可以采用拼字符串的方式傳遞參數
?* 可以采用 ?來傳遞參數(索引從0開始)
?* 可以采用 :參數名 來傳遞參數
?* 如果傳遞多個參數,可以采用setParamterList方法
?* 在hql中可以使用數據庫的函數,如:date_format
?參見:SimpleConditionQueryTest.java ?
???
4)、hibernate也支持直接使用sql進行查詢
?參見:SqlQueryTest.java
5)、外置命名查詢
?* 在映射文件中采用<query>標簽來定義hql
?* 在程序中采用session.getNamedQuery()方法得到hql查詢串
?參見:Student.hbm.xml、NameQueryTest.java
?
6)、查詢過濾器?
?* 在映射文件中定義過濾器參數
?* 在類的映射中使用這些參數
?* 在程序中啟用過濾器
?參見:Student.hbm.xml、FilterQueryTest.java
?
7)、分頁查詢【重要】?
?* setFirstResult(),從0開始
?* setMaxResults,每頁顯示多少條數據
?參見:PageQueryTest.java
????
8)、對象導航查詢,在hql中采用 . 進行導航【重要】
?參見:ObjectNavQueryTest.java
?
9)、連接查詢【重要】
?* 內連
?* 外連接(左連接/右連接)?
?參見:JoinQueryTest.java
?
10)、統計查詢【重要】
?參見:StatQueryTest.java
?
11)、DML風格的操作(盡量少用,因為和緩存不同步)
?參見:DMLQueryTest.java
13、Hibernate中的緩存
?1)、一級緩存
session 中一級緩存的生命周期和session的相同
由于load使用了session中的一級緩存 所以第二次的load 并不會發sql 因為在session的緩存中還存在
相同的數據。
由于get使用了session中的一級緩存 所以第二次的get 并不會發sql 因為在session的緩存中還存在相
同的數據。
?? ?會發出查詢 id 的 sql(使用一級緩存才會發出) 但是不會發出查詢對象的 sql 因為Iterate
查詢支持緩存。
在save的時候會在緩存中保存一份當前對象的引用。
session.clear();//全部清除
2)、二級緩存
???? <!-- 指定二級緩存的提供者 -->
??? <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
??? <!-- 指定是否使用二級緩存 默認為true -->
<property name="cache.use_second_level_cache">true</property>
使用ehcache.xml這個配置文件來配置二級緩存。
session 中二級緩存的生命周期和sessionFactory的相同,所以又稱為 sessionFactory 級緩存,二級
緩存只能用于存儲實體。
3)、三級緩存
??? <!-- 使用查詢緩存 默認為false-->
??? <property name="cache.use_query_cache">true</property>
queryCache生命周期和sessionFactory的相同。
但是在數據庫里面的數據改變的時候,queryCache中的對象失效。
QueryCache的生命周期與session無關。
Iterate 接口不支持 QueryCache。
這里使用list 來查詢實體對象 并開啟了QueryCache 由于QueryCache 會存儲實體的主鍵值,而list 在
查詢實體的時候不會使用緩存 所以list會使用QueryCache的實體的主鍵值 去查詢相應的,實體,由于
它會現在緩存中查找實體對象 如果不存在則會發出sql到數據庫中查詢 這里沒有配置二級緩存 ,又重
開了session所以在緩存中不存在實體對象 所以會根據在QueryCache 中的實體主鍵值發出sql到數據庫
中查詢。
因為開啟了二級緩存,QueryCache 會存儲查詢出來的實體的主鍵,而list會根據在QueryCache中的 主
鍵值到二級緩存中查找相應的實體,所以不會發出sql(list接口不會使用一級緩存但是能夠利用這種方
法使用QueryCache 和 二級緩存)。
14、抓取策略
?1)、fetch = "select" 抓取策略 發兩個select語句;fetch = "join" 抓取策略 使用外連接
查詢。
2)、在集合中的抓取策略
??使用 load
? * fetch = "select" 抓取策略 發兩條sql
? * fetch = "join" 發一條sql 采用外連接查詢
?使用 HQL
* fetch = "select" 抓取策略 發兩條sql 和加載對象方式一樣,每次每個實體的集合時會發sql
* fetch = "subselect" 將會在查詢實體的集合時將所有查詢的實體的集合發一次sql 全部查詢出來
3)、測試 batch – size
?batch-size="3"在集合中設置。
?