1. 程式人生 > >【Java】Hibernate框架筆記I

【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&amp;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值,值越大發送語句越少