【Java】Hibernate框架筆記I
目錄
0.orm思想(object relational mapping)
orm思想是hibernate的核心思想,什麼是orm思想?
1)讓實體類和資料庫表進行一一對應關係--->實體類和資料庫表的對應、實體類屬性和表的欄位的對應
2)操作資料時不用操作資料庫表,而是操作表對應類物件的屬性(需要用到hibernate封裝的session物件)
1.Hibernate的兩種配置檔案
1.1對映關係的配置檔案
1.1.1位置和命名:
(hibernate通過核心配置檔案來讀取,不會直接讀取,所以位置和名字可隨意)
對映關係指的就是 實體類和資料庫表之間的對映
*建議:在實體類所在包裡面建立,命名為:實體類名稱.hbm.xml
1.1.2 XML約束
使用線上讀取DTD約束的方式來進行XML約束
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
1.1.3配置檔案的格式
需要配置的對映關係有兩個,一個是類和表的對映,一個是類屬性和表字段的對映
<hibernate-mapping> <!-- 1 配置類和表對應 class標籤 name屬性:實體類全路徑 table屬性:資料庫表名稱 --> <class name="cn.itcast.entity.User" table="t_user"> <!-- 2 配置實體類id和表id對應 hibernate要求實體類有一個屬性唯一值 hibernate要求表有欄位作為唯一值 --> <!-- id標籤 name屬性:實體類裡面id屬性名稱 column屬性:生成的表字段名稱 --> <id name="uid" column="uid"> <!-- 設定資料庫表id增長策略 native:生成表id值就是主鍵自動增長 --> <generator class="native"></generator> </id> <!-- 配置其他屬性和表字段對應 name屬性:實體類屬性名稱 column屬性:生成表字段名稱 --> <property name="username" column="username"></property> <property name="password" column="password"></property> <property name="address" column="address"></property> </class> </hibernate-mapping>
1.2核心配置檔案
1.2.1位置和命名
(hibernate會直接讀取的,所以位置和名字規定好了)
- 位置:必須src下面
- 名稱:必須hibernate.cfg.xml
1.2.2 XML約束
同樣也是線上讀取DTD來進行約束
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
1.2.3配置檔案的格式
需要配置的有三部分:
1)資料庫資訊
2)hibernate資訊
3)將上述的對映檔案通過配置來讓hibernate來讀取
<hibernate-configuration>
<session-factory>
<!-- 資料庫資訊 必須-->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate_1?useUnicode=true&characterEncoding=UTF-8</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">532077936</property>
<!-- hibernate資訊 可選 -->
<!-- 輸出底層sql語句 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化輸出的sql語句 -->
<property name="hibernate.format_sql">true</property>
<!-- 讓hibernate在沒有建立表且有對應實體類的時候建立表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 配置資料庫方言 比如mysql中的limit oracle中的rownum 不同的資料庫用的value不同 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 將對映檔案放到核心配置檔案中 -->
<mapping resource="com/tencent/entity/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
2.Session是什麼?怎麼來的?
>>Session是對於hibernate開發人員一個很重要的介面,主要是用於檢測持久物件的變化,並及時重新整理資料庫,有時候也可以叫做持久層管理器,Session是非執行緒安全的,所以要一個執行緒對應一個Session
>>Session是由SessionFactory,一般一個專案只有一個SessionFactory,是公用的
>>SessionFactory是由Configuration的物件通過configure()來建立的,通過此方法就讀取了預設位置的核心配置檔案
也可以通過傳遞引數來指定核心配置檔案的位置
3.實體類物件的三種狀態
1)瞬時態:物件裡面沒有id值,物件與session沒有關聯
2)持久態:物件裡面有id值,物件與session關聯
3)託管態:物件有id值,物件與session沒有關聯
4.Update、Save、saveOrUpdate方法區別
4.1 Session.update();
>>瞬時態:
無法儲存,丟擲異常
org.hibernate.TransientObjectException: The given object has a null identifier
>>持久態:
不修改id,就直接覆蓋
修改id,
①如果id不存在丟擲異常
org.hibernate.HibernateException: identifier of an instance of com.entity.User was altered from 1 to 2
②如果id存在(和之前的id不同),
也會丟擲異常
org.hibernate.HibernateException: identifier of an instance of com.entity.User was altered from 1 to 297e7cba
>>託管態:
對於存在的id會以所有 實體類物件的屬性值 來覆蓋 原有表的對應欄位
對於不存在的id不會進行任何操作
4.2 Session.save();
>>瞬時態:
建立一條新的資料,欄位值 對應 類物件屬性值
>>持久態:
結果同update();
>>託管態:
id不管存不存在,都將建立一條新的資料,欄位值 對應 類物件屬性值
4.2 Session.saveOrUpdate();
>>瞬時態:
結果同save();
>>持久態:
結果同update();
>>託管態:
結果同update();
綜上實驗結果,對於session取回來的持久態資料,是不能更改其id的,會丟擲異常
對於持久態的資料,使用三種方法得到的結果都是一樣的
當需要建立新條目的時候,需要使用save方法,不管是瞬時態還是託管態都會建立新資料(不管id是否已存在)
而需要更新條目時(不要新條目),就使用update
5.Hibernate一級快取的內部執行方式
6.Hibernate三種查詢query/criteria/sqlquery物件的使用
***這裡只是舉例了三種物件最簡單的用法(查詢表所有欄位)
6.1 query
hql:hibernate query language
6.2 criteria
6.3 sqlquery
7.一對多以及多對多關係的對映配置、級聯儲存和刪除,inverse屬性
7.1一對多: 用一個外來鍵來維繫兩個表
①兩個實體類相互表示
eg:一個老師對應多個學生,在老師實體類中新增一個學生類的集合屬性,在學生實體類新增一個老師類集合屬性
②對映配置
配置每個實體類中新增的對應的屬性(另一個實體類)
>>>學生表配置檔案中:
<many-to-one name="teacher" class="com.entity.Teacher" column="stid">
*name屬性:老師的實體類名稱為Teacher,所以用teacher
*class屬性:Teacher類的全路徑
*column屬性:外來鍵名稱
>>>老師表配置檔案中:
<set name="setStudent" cascade="save-update">
<key column="stid"></key>
<one-to-many class="com.entity.Student"/>
</set>
*set的name屬性:寫老師類裡面的學生類set集合名稱
*cascade="save-update":級聯儲存的時候只需要將學生放到老師的學生集合下就可以了,不用再將老師放到學生的老師屬性下
*column:外來鍵名稱
*class:學生類全路徑
級聯儲存、刪除 就是
比如建立一個老師,要給多個學生在老師下面,儲存到資料庫就是級聯儲存。刪除也同理
Teacher tea = new Teacher();
tea.setName("李");
tea.setPhone("110");
Student stu = new Student();
stu.setStu_name("小巨集");
// 把學生放到老師的學生集合下面
tea.getSetStudent().add(stu);
//如果沒有cascade="save-update"
//就需要這一句stu.setTeacher(tea);
// 儲存到資料庫
session.save(tea);
③把對映檔案引入到核心配置檔案中
7.2多對多: 用一個表(由外來鍵構成的表)來維繫另外兩個表
eg:一個使用者有多個角色,一個角色可以由多個使用者扮演
①同一對多,只不過兩個實體類新增的都是對應另一個表的集合
②對映配置
user_role:由外來鍵構成的維繫 使用者表 和 角色表 的第三張表
③把對映檔案引入到核心配置檔案中
一般都不用這種方法,因為這樣第三張表只能存放兩個欄位(兩個id)
一般都是建立多一個實體類用於當做第三張表,將多對多 變成兩個一對多
7.3 inverse屬性來取消雙向維護,減少重複sql
在hibernate中,是雙向維護外來鍵的
(eg:一個老師對應多個學生)
在老師和學生都需要維護外來鍵,修改老師會修改一次外來鍵(造成兩個update),修改學生也會修改一次外來鍵(造成兩個update)
>>解決方式:
在一對多中:
讓其中一方放棄維護外來鍵 ---> 在set標籤上使用 inverse="true" 屬性 表示放棄維護
讓 一 的那一方放棄維護外來鍵
>>比擬:
就好像 所有學生都認識一個老師 但老師不一定認識所有學生(老師放棄了維護學生集合外來鍵)
8.五種查詢方式
8.1 物件導航查詢
用session查到一個物件後,再用該物件的get方法獲取到該物件中的物件(屬性)
Student stu = session.get(Student.class, "1");
Teacher teacher = stu.getTeacher;
8.2 OID查詢
根據id查詢記錄
(1)呼叫session裡面的get方法實現
session.get(Student.class, "1");
8.3 HQL查詢(Query)
hibernate query language 使用Query物件來進行查詢操作
8.4 QBC查詢(Criteria)
(1)建立Criteria物件
(2)呼叫方法得到結果
8.5 本地SQL查詢(SqlQuery)
用本地的資料庫來進行查詢
(1)建立SqlQuery物件
(2)呼叫方法得到結果
9.離線查詢(DetachedCriteria)
使用原因:多條件查詢,查詢或與關係不明確時 等 查詢的條件不明確,要使用者傳遞查詢條件時需要用到。
使用方法:使用DetachedCriteria來構造查詢條件
(1)建立物件DeatchedCriteria criteria = DetachedCriteria.forclass(Class);
(2)增加條件 criteria.add() / criteria.addOrder() /...
(3)執行查詢
10.迫切 內(左外) 連線 fetch 返回物件不是陣列(Query)
有無迫切的區別:迫切返回的list裡面每個部分是物件,沒有迫切返回的list裡面是陣列
主要用法就是在hql中加入關鍵字fetch + 子物件(比如學生類裡面的老師)
from Customer c inner join fetch c.setLinkMan
from Customer c left outer join fetch c.setLinkMan
但是沒有迫切右外連線?
11.hibernate檢索策略(立即查詢和延遲查詢(又分兩個)-->優化)
(1)立即查詢:根據id查詢,呼叫get方法,一呼叫get方法馬上傳送語句查詢資料庫
(2)延遲查詢:根據id查詢,還有load方法,呼叫load方法不會馬上傳送語句查詢資料,
只有需要get物件裡面的值時候才會傳送語句查詢資料庫
類級別延遲:根據id查詢返回實體類物件,呼叫load方法不會馬上傳送語句
關聯級別延遲:查詢某個客戶,再查詢這個客戶的所有聯絡人,查詢客戶的所有聯絡人的過程是否需要延遲,這個過程稱為關聯級別延遲
在對映檔案中進行配置實現
(1)根據客戶得到所有的聯絡人,在客戶對映檔案中配置
2 在set標籤上使用屬性
(1)fetch:值select(預設)
(2)lazy:值
- true:延遲(預設)
- false:不延遲
- extra:極其延遲
12.批量抓取
查詢所有的學生,以及學生下所對應的老師,用兩個FOR迴圈會產生大量的SQL
在老師的對映檔案中,set標籤配置
batch-size值,值越大發送語句越少