Hibernate5基本教程

第一部分

Hibernate是什麼,它有什麼作用?

Hibernate它是一個輕量級的jdbc封裝,也就是說,我們可以使用hibernate來完成原來我們使用jdbc完成操作,就是與數據庫的交互操作。它是在dao層去使用的。

對象關係映射(英語:Object Relation Mapping,簡稱ORM,或O/RM,或O/R mapping)。簡單說,我們使用orm可以將我們的對象與我們的類去進行映射,使的我們可以去操作對象就完成對錶的操作。

創建數據庫與表

CREATE DATABASE hibernateTest;

USE hibernateTest;

CREATE TABLE t_customer(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20),
	address VARCHAR(50)
)

創建實體類

導入hibernate框架相關依賴jar包

導入lib/required下所有的jar

導入數據庫的驅動jar包

日誌相關jar包

將hibernate/project/etc/log4j.properties文件導入到工程src下.

Hibernate的相關配置文件

有兩種:

         1.xxx.hbm.xml 它主要是用於描述類與數據庫中的表的映射關係.

         2.hibernate.cfg.xml 它是hibernate框架核心配置文件。

映射配置文件

         位置:它要與實體類在同一個包下。

         名稱 :類名.hbm.xml

         約束:

<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

可以在hibernate的核心的jar包下的org.hibernate包下查找到

核心配置文件

它主要是hibernate框架所使用的,它主要包含了連接數據庫相關信息,hibernate相關配置等。

位置:在src下創建一個hibernate.cfg.xml

約束:

約束文件所在位置:hiberante核心jar包下的org.hibernate包下                

在這個文件中如何配置?

可以參考 hibernate-release-5.0.7.Final\project\etc\hibernate.properties文件

Hibernate快速 入門開發測試

Hibernate執行原理總結

hibernate工作原理:

1、通過Configuration().configure();讀取並解析hibernate.cfg.xml配置文件

2、由hibernate.cfg.xml中的<mappingresource="com/xx/User.hbm.xml"/>讀取解析映射信息。

3、通過config.buildSessionFactory();//得到sessionFactory。

4、sessionFactory.openSession();//得到session。

5、session.beginTransaction();//開啓事務。

6、persistent operate;

7、session.getTransaction().commit();//提交事務

8、關閉session;

9、關閉sessionFactory;

Hibernate的配置詳解

Hibernate中我們使用時主要有兩種配置文件

核心配置文件  hibernate.cfg.xml

對於hibernate的核心配置文件它有兩種方式:

  1. hibernate.cfg.xml
  2. hibernate.properties

我們在開發中使用比較多的是hibernate.cfg.xml這種方式,原因它的配置能力更強,易於修改。我們主要講解的是hibernate.cfg.xml配置。

可以加載數據庫相關信息:

hibernate相關配置:

加載映射配置文件:

對於hibernate.cfg.xml配置文件中的內容可以參考hibernate/project/etc/hibernate.properties的配置

配置這個屬性後,我們可以進行表的自動創建

Create-drop 每次都會創建一個新的表,執行完成後刪除。一般在測試中使用

Create   每次都會創建一個新的表,一般是在測試中使用

update 如果數據庫中有表,不創建,沒有表創建,如果映射不匹配,會自動更新表結構(只能添加)

validate  只會使用存在的表,並且會對映射關係進行校驗.

映射配置文件   xxx.hbm.xml

         映射配置文件它的名稱是類名.hbm.xml,它一般放置在實體類所在的包下。

         這個配置文件的主要作用是建立表與類的映射關係。

1、統一聲明包名,這樣在<class>中就不需要寫類的全名.

2、關於<class>標籤配置

name屬性:類的全名稱

table 表的名稱,可以省略,這時表的名稱就與類名一致

catalog屬性:數據庫名稱 可以省略.如果省略,參考核心配置文件中url路徑中的庫名稱

3、關於<id>標籤

首先它必須存在。<id>是用於建立類中的屬性與表中的主鍵映射。

name 類中的屬性名稱

column 表中的主鍵名稱  column它也可以省略,這時列名就與類中屬性名稱一致

length 字段長度

type屬性 指定類型

<generator>它主要是描述主鍵生成策略.

4、關於<property>標籤

它是描述類中屬性與表中非主鍵的映射關係。

關於hibernate的映射文件中類型問題:

對於type屬性它的取值,可以有三種:

  1. java中的數據類型
  2. hibernate中的數據類型
  3. SQL的數據類型

默認是hibernate中數據類型

Hibernate常用API

Hibernate的核心類和接口一共有6個,分別爲:Session、SessionFactory、

Transaction、Query、Criteria和Configuration。這6個核心類和接口在任何開發中都會用到

Configuration

它主要是用於加載hibernate配置.

Configuration config=new Configuration().config(); 主要加載src下的hibernate.cfg.xml

Configuration config=new Configuration();主要加載的src下的hibernate.properties

Configuration config=new Configuration().config(核心配置文件名稱);加載指定的名稱的配置文件

問題:我們是在hibernate.cfg.xml文件中有xxx.hbm.xml文件的位置。如果我們使用的是hibernate.properties這種核心配置,它如何加載映射配置?

SessionFactory

首先SessionFactory它的獲取是通過Configuration得到。

SessionFactory接口負責初始化Hibernate。它充當數據存儲源的代理,並負責創建Session對象。這裏用到了工廠模式。需要注意的是SessionFactory並不是輕量級的,因爲一般情況下,一個項目通常只需要一個SessionFactory就夠,當需要操作多個數據庫時,可以爲每個數據庫指定一個SessionFactory。通過SessionFactory可以得到Session:

是從連接池中獲取一個連接:

獲取一個與線程綁定的Session。

SessionFactory它不是輕量級的,不要頻繁創建關閉它。在一個項目中有一個SessionFactory就可以,通過SessionFactory來獲取Session進行操作。

問題:怎樣可以保證在一個項目中所使用的SessionFactory是同一個呢?

問題:SessionFactory內部還維護了一個連接池,如果我們要想使用c3p0連接池,應該怎樣處理?

1、我們要導入c3p0的相關jar包

在hibernate/lib/options下有關於c3p0連接池jar包

2、在hibernate.cfg.xml文件中配置c3p0連接

可以查看etc/hibernate.properties中關於c3p0的配置

Session

Session接口負責執行被持久化對象的CRUD操作(CRUD的任務是完成與數據庫的交流,包含了很多常見的SQL語句)。但需要注意的是Session對象是非線程安全的。

問題:我們如何解決session的安全問題?

         我們只需要在方法內部來使用Session就可以。

問題:Session如何獲取到?

SessionFactory.openSession() ;  相當於直接通過SessionFactory創建一個新的Session,使用完成後要手動調用close來關閉。

SessionFactory.getCurrentSession(); 獲取一個與線程綁定的Session,當我們提交或事務回滾後會自動關閉。

Session常用的方法:

         save  保存對象

         update 修改操作

         delete刪除

         get/load 根據id進行查詢

         savenOrUpdate 執行save或update操作

         createQuery()獲取一個Query對象

         CreateSQLQUery()獲取一個可以操作sql的SQLQuery對象

         createCriteria() 獲取一個Criteria它可以完成條件查詢

Transaction

Transaction接口主要用於管理事務,它是hibernate的事務接口,對底層的事務進行了封裝。使用它可以進行事務操作。

commit 事務提交

rollback 事務回滾

問題:如果獲取一個Transaction對象?

Session.beginTransaction();

問題:如果在程序中沒有開啓事務,是否存在事務?

有事務,session的每一個操作就會開啓一個事務。默認情況下事務是不會自動提交的。

默認不自動提交:

事務自動提交:

Query

Query接口讓你方便地對數據庫及持久對象進行查詢,它可以有兩種表達方式:HQL語言或本地數據庫的SQL語句。Query經常被用來綁定查詢參數、限制查詢記錄數量,並最終執行查詢操作。

通過Query主要完成查詢操作.

我們通過Query可以執行hql語句.

Query query=Session.createQuery(hql);

下面這個可以執行sql語句

SQLQUery sqlQuery=Session.createSQLQuery(sql);

SQLQuery是Query的子.

查詢所有操作---使用HQL

分頁查詢

查詢指定列信息

Select name ,address from Customer; 得到的是List<Object[]>結果

要想得到List<Customer>結果

  1. 在Customer類中生成以name,address爲參數的構造,注意,無參數構造也要有。
  2. Select new Customer(name,address) from Customer;

條件查詢

可以使用where關鍵字

//無名稱參數  from Customer where name=?

對其進行賦值   query.setParameter(0,”張三”)

//有名稱參數  from Customer where name=:myname;

對其進行賦值  query.setParameter(“myname”,”李四”);

//如果查詢結果可以保證就是唯一 的,我們可以使用

query. uniqueResult()來得到一個單獨對象.

執行本地SQL

要想執行本地sql

SQLQuery sqlQuery=session.createSqlQuery(String sql);

使用addEntity方法來將結果封裝到指定的對象中,如果不封裝,得到的是List<Object>

如果sql中有參數,我們使用setParameter方法完成參數傳遞。

如果結果就是一個可以使用uniqueResult()來得到一個單獨對象。

Criteria

Criteria接口與Query接口非常類似,允許創建並執行面向對象的標準化查詢。值得注意的是Criteria接口也是輕量級的,它不能在Session之外使用。

首先我想使用Criteria,必須得到Criteria

Criteria criteria=Session.createCriteria()

查詢所有操作

Session.createCriteria(實體類.class)得到一個Criteria對象,調用list查詢所有

分頁操作與query的方法一樣

setFirstResult()    setMaxResults()

條件查詢

criteria.add(Restrictions.eq(“name”,”xxxx”));

criteria.add(Restrictions.or(Restricitons.eq(),Restrictions.list()…..))

我們使用Criteria可以更加面向對象去操作,它非常適合進行多條件組合查詢。

第二部分

Hibernate持久化類與主鍵生成策略

Hibernate持久化類

什麼是持久化類?

Persistent Object  (PO)

PO=POJO+hbm映射配置

對於hibernate中的PO編寫規則:

1、必須提供一個無參數的public構造方法。

2、所有屬性要private ,對外提供public 的get/set方法。

3、在PO類必須提供一個標識屬性,讓它與數據庫中的主鍵對應,我們管這個屬性叫OID。

4、PO類中的屬性儘量使用基本數據類型的包裝類。Int-->Integer  double-->àDouble  float-->Float

5、PO類它不能使用final修飾符。

OID作用:OID指的是與數據庫中表的主鍵對應的屬性。Hibernate框架它是通過OID來區分不同的PO對象,如果在內存中有兩個相同的OID對象,那麼hibernate認爲它們是同一個對象。

爲什麼PO類屬性它要使用包裝類型?

使用基本數據類型是沒有辦法去描述不存在概念,如果使用包裝類型,它就是一個對象,對於對象它的默認值是null.

PO類不可以使用final修飾?(hibernate中的get/load方法的區別): Get/load方法它們都是根據id去查詢對象。

1、get直接得到了一個持久化類型對象,它就是立即查詢操作。load它得到的是持久化類開的代理類型對象(子類對象)。它採用了一種延遲策略來查詢數據。

2、get方法在查詢時,如果不存在返回nullload方法在查詢時,如果不存在,會產生異常ObjectNotFoundException。

Hibernate主鍵生成策略

Hibernate中定義的主鍵類型包括:自然主鍵和代理主鍵:

自然主鍵:具有業務含義字段作爲主鍵,比如:學號、身份證號。

代理主鍵:不具有業務含義字段作爲主鍵(例如 自增id),比如:mysql自增主鍵,oracle序列生成的主鍵、uuid()方法生成的唯一序列串。

建議:企業開發中使用代理主鍵!   

主鍵生成器

描述

increment

代理主鍵。由hibernate維護一個變量,每次生成主鍵時自動以遞增。

問題:如果有多個應用訪問一個數據庫,由於每個應用維護自己的主鍵,所以此時主鍵可能衝突。建議不採用。

優點:可以方便跨平臺

缺點:不適合高併發訪問

identity

代理主鍵。由底層數據庫生成表識符。條件是數據庫支持自動增長數據類型。比如:mysql的自增主鍵,oracle不支持主鍵自動生成。

如果數據庫支持自增建議採用。

優點:由底層數據庫維護,和hibernate無關

缺點:只能對支持自動增長的數據庫有效,例如mysql

sequence

代理主鍵。Hibernate根據底層數據庫序列生成標識符。條件是數據庫支持序列。比如oracle的序列。

如果數據庫支持序列建議採用。

優點:由底層數據庫維護,和hibernate無關

缺點:數據庫必須支持sequence方案例如oracle

native

代理主鍵。根據底層數據庫對自動來選擇identity、sequence、hilo

由於生成主鍵策略的控制權由hibernate控制,所以不建議採用。

優點:在項目中如果存在多個數據庫時使用

缺點:效率比較低

uuid

代理主鍵。Hibernate採用128bit位的UUID算法來生成標識符。該算法

能夠在網絡環境中生成唯一的字符串標識符。

此策略可以保證生成主鍵的唯一性,並且提供了最好的數據庫插入性能和數據庫平臺的無關性。建議採用。

優點:與數據庫無關,方便數據庫移植,效率高,不訪問數據庫就可以直接生成主鍵值,並且它能保證唯一性。

缺點:uuid長度大(32位),佔用空間比較大,對應數據庫中類型 char  varchar,對應id的類型爲String類型.

assigned

自然主鍵。由java程序負責生成標識符。

不建議採用。

儘量在操作中避免手動對主鍵操作

Hibernate持久化對象狀態

持久化對象三種狀態

1、瞬時態:也叫做臨時態或自由態,它一般指我們new出來的對象,它不存在OID,與hibernate session無關聯,在數據庫中也無記錄。它使用完成後,會被jvm直接回收掉,它只是用於信息攜帶。簡單說:無OID 與數據庫中的信息無關聯,不在session管理範圍內。

2、持久態:在hibernate session管理範圍內,它具有持久化標識OID它的特點,在事務未提交前一直是持久態,當它發生改變時,hibernate是可以檢測到的。簡單說:有OID 由session管理,在數據庫中有可能有,也有可有沒有。

3、託管態:也叫做遊離態或離線態,它是指持久態對象失去了與session的關聯,託管態對象它存在OID,與session無關聯,在數據庫中有可能存在,也有可能不存在。對於託管態對象,它發生改變時hibernet不能檢測到。

持久化類三種狀態切換

判斷持久化類對象三種狀態:

  1. 是否有OID
  2. 判斷是否與session關聯

https://img-blog.csdnimg.cn/20181225221850133

 

1、瞬時態(new 出來的)

瞬時------à持久  save   saveOrUpdate

瞬時-----à脫管(遊離)  手動設置oid

2、持久態   它是由session管理

  持久-------瞬時   delete() 被刪除後持久化對象不在建議使用

   持久-----脫管  注意:session它的緩存就是所說的一級緩存

   evict(清除一級緩存 中指定的一個對象)

   clear(清空一級緩存)

    close(關閉,清空一級緩存)

3、脫管態   (它是無法直接獲取)

    脫管-----瞬時    直接將oid刪除

   脫管----持久  update  saveOrUpdate lock(過時)

Hibernate一級緩存

Hibernate的一級緩存就是指session緩存。

actionQueue它是一個行列隊列,它主要記錄crud操作的相關信息

persistenceContext它是持久化上下文,它其實是真正緩存。

在session中定義了一系列的集合來存儲數據,它們構成session緩存。

只要session沒有關閉,它就會一直存在。

當我們通過hibernate中的session提供的一些API例如 save  get  update等進行操作時,就會將持久化對象保存到session中,當下一次在去查詢(Ps,增刪改還是會查詢數據庫)緩存中具有的對象(OID值來判斷),就不會去從數據庫查詢,而是直接從緩存中獲取。

Hibernate的一級緩存存在的目的就是爲了減少對數據庫訪問。

在hibernate中還有一個二級緩存,它是SessionFactory級別緩存。

示例---演示一級緩存的存在

持久化對象具有自動更新數據庫能力

爲什麼持久化對象具有自動更新數據庫能力?

一級緩存常用API

一級緩存特點:

  1. 當我們通過session的save,update saveOrupdate進行操作時,如果一級緩存中沒有對象,會將這些對象從數據庫中查詢到,存儲到一級緩存。
  2. 當我們通過session的load,get,Query的list等方法進行操作時,會先判斷一級緩存中是否存在,如果沒有才會從數據庫獲取,並且將查詢的數據存儲到一級緩存中。
  3. 當調用session的close方法時,session緩存清空。

         clear 清空一級緩存.

         evict 清空一級緩存中指定的一個對象。

         refresh重新查詢數據庫,用數據庫中信息來更新一級緩存與快照

Hibernate常用API-Session補充

update

         udpate操作它主要是針對於脫管對象,持久對象具有自動更新能力。

         問題1:如果我們直接操作的對象是一個脫管對象,執行update會出現什麼情況?

Update操作時,如果對象是一個脫管對象,可以操作,它會將脫管對象轉換成持久對象再操作。

如果在session中出現相同的oid兩個對象,會產生異常

 

         問題2:脫管對象的oid如果在數據表中不存在,會報異常?

        

所以:在操作中,建議我們通過持久化對象來直接修改其操作。

saveOrUpdate

 如果對象是一個瞬時對象 --------執行save操作

如果對象是一個脫管對象---------執行update

如果是一個持久對象-------直接返回

delete

刪除一個脫管對象,與session關聯,在刪除

注意:如果執行delete操作,先刪除一級緩存,在刪除數據庫中的數據。

Hibernate關聯映射--數據對象三種關係

Hibernate框架基於ORM設計思想,它將關係型數據庫中的表與我們java中的類進行映射,一個對象就對應着表中的一條記錄,而表中的字段對應着類中的屬性。

數據庫中表與表之間存在着三種關係,也就是系統設計中的三種實體關係

一對一

原則有兩種:

  1. 唯一外鍵對應:在任意一方添加外鍵來描述對應關係
  2. 主鍵對應:一方的主鍵作爲另一方的主鍵

Class Employee{
	Private Archives archives;
}
Class Archives{
	Private Employee employee;
}

一對多(多對一)

客戶與訂單之間一對多關係(多對一)

建表原則:在多的一方添加外鍵來描述關聯關係

Class Customer{
	Private Set<Order> orders;
}

Class Order{
	Private Customer c;
}

多對多

例如學生與老師

建表原則:通過一張中間表來描述其對應關係

Class Student{
	Set<Teacher> ts;
}
Class Teacher{
	Set<Student> ss;
}

Hibernate關聯映射--一對多(多對一)

我們以客戶(Customer)與訂單(Order)爲例

實體類創建

訂單

客戶

Hbm映射文件編寫

Order.hbm.xml

Customer.hbm.xml

測試保存

上面操作是一種雙向關聯

問題:我們可不可以只保存訂單或只保存客戶完成保存操作?

測試單向關聯保存

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: cn.itheima.oneToMany.Customer

…………..

這個異常代表提一個持久化對象關聯了一個瞬時對象。

我們可以使用級聯操作來解決上述的問題.

我們現在要做的是保存訂單時保存客戶,需要在訂單的hbm配置文件中修改

設置cascade=save-update 那麼在保存訂單時就可以自動將客戶保存。

如果我們要完成保存客戶時,保存訂單

雙向關聯維護

我們在開發中要配置雙向關聯配置。---------可以通過任意一方來操作對方

在操作代碼,儘量來要進行單向關聯。------可以儘量資源浪費。

在雙向關聯中,會存在多餘的update語句。

我們可以使用inverse屬性來設置,雙向關聯時由哪一方來維護表與表之間的關係。

Inverse它的值如果爲true代表,由對方來維護外鍵。

Inverse它的值如果爲false代表,由本方來維護外鍵。

關於inverse的取值:

         外鍵在哪一個表中,我們就讓哪一方來維護外鍵。

對象導航

級聯刪除

我們在刪除客戶時,也要刪除訂單,如果沒有做級聯,那麼這個操作是不允許。

爲了維護數據完整性


想要完成操作:我們可以在客戶中添加cascade=”delete”;

delete-orphan用法

cascade總結

使用cascade可以完成級聯操作

它可常用取值:

         none這是一個默認值

save-update,當我們配置它時,底層使用save update或save-update完成操作,級聯保存臨時對象,如果是遊離對象,會執行update.

delete 級聯刪除

delete-ophan 刪除與當前對象解除關係的對象。(刪除其中指定的一個訂單)

all 它包含了save-update  delete操作

all-delete-orphan 它包信了delete-orphan與all操作

筆試題:cascade與inverse有什麼區別?

 cascade它是完成級聯操作。Inverse它只有在雙向關聯情況下有作用,它來指定由哪一方維護外鍵。外鍵在哪一個表中,就由哪一個表維護外鍵。

第三部分

Hibernate註解開發

在hibernate中我們使用註解,可以幫助我們簡化hbm文件配置。

PO類註解配置

@Entity 聲明一個實體

@Table來描述類與表對應

@Id來聲明一個主鍵

@GenerateValue 用它來聲明一個主鍵生成策略

默認情況下相當於native

可以選擇的主鍵生成策略 AUTO IDENTITY SEQUENCE

@Column來定義列

注意:對於PO類中所有屬性,如果你不寫註解,默認情況下也會在表中生成對應的列。

列的名稱就是屬性的名稱

@Temporal來聲明日期類型

可以選擇

TemporalType.DATA   只有年月日 

TemporalType.TIME   只有小時分鐘秒

TemporalType.TIMESTAMP 有年月日小時分鐘秒

我們最終需要在hibernate.cfg.xml文件中將我們類中的註解配置引用生效

問題:1.如果我們主鍵生成策略想使用UUID類型?

問題2:如果設定類的屬性不在表中映射?

對於我們以上講解的關於屬性配置的註解,我們也可以在其對應的getXxx方法去使用

一對多(多對一)

@OneToMany

@ManyToOne

以Customer與Order爲例

Customer類

Order類

示例:保存客戶時,保存訂單

對於這個示例我們需要在Customer中配置cascade操作,save-update

第一種方式,可以使用JPA提供的註解

第二種方式:可以使用hibernate提供的註解(建議使用)

以下是示例代碼

執行後的結果


訂單中沒有關聯客戶的id,爲什麼?

原因:我們在Customer中配置了mappedBy=”c”它代表的是外鍵的維護由Order方來維護,而Customer不維護,這時你在保存客戶時,級聯保存訂單,是可以的,但是不能維護外鍵,所以,我們必須在代碼中添加訂單與客戶關係。

擴展關於刪除:關於hibernate註解@Cascade中的DELETE_ORPHAN過時

使用下面方案來替換過時方案

Hibernate關聯映射-多對多

我們使用註解完成多對多配置.

描述學生與老師.

使用@ManyToMany來配置多對多,只需要在一端配置中間表,另一端使用mappedBy表示放置外鍵維護權。

創建PO類

Teacher類中

Student類中

級聯保存操作測試

   因爲我們將外鍵的維護權利由Student來維護,我們演示保存學生時,將都也級聯保存。

我們在Student類中配置了級聯

級聯刪除操作測試

Hibernate關聯映射-一對一

以人與身份證號爲例

一對一操作有兩種映射方式:

  1. 在任意一方添加外鍵
  2. 主鍵映射

外鍵映射

創建實體

User類

上述配置,t_user表放棄對外鍵的維護權利

IDCard類

joinColumn指定外鍵列名稱,當前配置外鍵是在t_idcard表中

測試代碼:

主鍵映射(瞭解)

以Husband與Wife爲例

Wife的主鍵生成策略是identity

@PrimaryKeyJoinColumn 說明husband與wife是使用主鍵映射

Husband的主鍵我們設置成參考wife的主鍵方式

測試操作:

Hibernate檢索方式概述

對數據庫操作中,最常用的是select.使用hibernate如何select操作。

分爲五種:

1導航對象圖檢索方式,根據已加載的對象導航到其它對象。

2.OID檢索方式,按照對象的OID來檢索對象。

3.HQL檢索方式,使用面向對象的HQL查詢語言。

4.QBC檢索方式,使用QBC(Query by Criteria)API來檢索對象,這種API封裝了基於字符串形式的查詢語句,提供了更加面向對象的查詢接口。

5.本地SQL檢索方式,使用本地數據庫的SQL查詢語句。

導航對象圖檢索方式

         Customer c=session.get(Customer.class,2);

         c.getOrders().size()

         通過在hibernate中進行映射關係,在hibernate操作時,可以通過導航方式得到

         其關聯的持久化對象信息。

OID檢索方式

         Session.get(Customer.class,3);

         Session.load(Order.class,1);

         Hibernate中通過get/load方法查詢指定的對象,要通過OID來查詢。

HQL

HQL是我們在hibernate中是常用的一種檢索方式。

HQL(Hibernate Query Language)提供更加豐富靈活、更爲強大的查詢能力

因此Hibernate將HQL查詢方式立爲官方推薦的標準查詢方式,HQL查詢在涵蓋Criteria查詢的所有功能的前提下,提供了類似標準SQL語 句的查詢方式,同時也提供了更加面向對象的封裝。完整的HQL語句形式如下: Select/update/delete…… from …… where …… group by …… having …… order by …… asc/desc 其中的update/delete爲Hibernate3中所新添加的功能,可見HQL查詢非常類似於標準SQL查詢。

基本步驟:

  1. 得到Session
  2. 編寫HQL語句
  3. 通過session.createQuery(hql)創建一個Query對象
  4. 爲Query對象設置條件參數
  5. 執行list查詢所有,它返還的是List集合  uniqueResut()返回一個查詢結果。

數據準備

基本檢索

From 類名;

排序檢索

條件檢索

分頁檢索

分組統計檢索

分組  group by

統計  count   max  min  avg  sum

投影檢索

我們主要講解是關於部分屬性查詢,可以使用投影將部分屬性封裝到對象中。

注意:我們必須在PO類中提供對應屬性的構造方法,也要有無參數構造。

命名檢索

我們可以將hql語句先定義出來,在使用時通過session.getNamedQuery(hqlName);得到一個Query,在執行.

問題:hql定義在什麼位置?

         1.如果你有hbm配置文件,那麼當前的hql操作是對哪一個實體進行操作,就在哪一個  實體的配置文件中聲明。

        

         2.如果是使用註解來描述PO的配置。

                   我們直接在PO類中使用

如何使用?

        

        

QBC

QBC(query by criteria),它是一種更加面向對象的檢索方式。

QBC步驟:

         1.通過Session得到一個Criteria對象   session.createCriteria()

         2.設定條件  Criterion實例 它的獲取可以通過Restrictions類提供靜態。

                   Criteria的add方法用於添加查詢條件

  1. 調用list進行查詢  criterfia.list.

 

基本檢索

        

排序檢索

注意在criteri.addOrder()方法的參數使用的Order是hibernate中的對象

條件檢索

分頁檢索

統計分組檢索

Count  sum  avg  max  min

離線條件檢索

本地SQL

本地sql也支持命名查詢。

可以將sql語句定義在hbm文件中,也可以使用註解。

本地命名sql註解定義

如果執行這個命名的sql會產生異常

出現問題的原因:是hibernate不知道執行select * from t_customer後如果將結果封裝。

第四部分

多表操作

SQL多表操作

1.交叉連接  CROSS JOIN  會產生迪卡爾積

SELECT * FROM t_customer CROSS JOIN t_order;

2.內連接  INNER JOIN  ON

SELECT * FROM t_customer AS c INNER JOIN t_order AS o ON c.id=o.c_customer_id;

使用內連接它只能將有關聯的數據得到。

隱式內連接  使用 "逗號"將表分開,使用WHERE來消除迪卡爾積

SELECT * FROM t_customer c ,t_order o WHERE c.id=o.c_customer_id;

3.外連接  左外LEFT OUTER JOIN    右外RIGHT OUTER JOIN

OUTER可以省略

SELECT * FROM t_customer c LEFT OUTER JOIN t_order o ON c.id=o.c_customer_id;

HQL多表操作

         Hql多表操作分類:

  1. 交叉連接
  2. 內連接
    1. 顯示內連接
    2. 隱式內連接
    3. 迫切內連接
  3. 外連接

左外連接

迫切左外連接

右外連接

注意:在hibernate中有迫切連接的概念,而sql中沒有。

內連接

顯示內連接

顯示內連接使用的是inner join with

隱式內連接

隱式內連接也我們在sql中操作不一樣,它是通過”.”運算符來關聯

迫切內連接

迫切內連接得到的結果是直接封裝到PO類中,而內連接得到的是Object[]數組,數組中封裝的是PO類對象。

外連接

Hibernate事務管理

事務介紹

問題:什麼是事務?

         事務就是邏輯上的一組操作,組成這組操作的各個單元要麼全部成功,要麼全都失敗。

問題:事務四個特性?

         原子性:不可分割

         一致性:事務在執行前後,要保證數據的一致。

         隔離性:一個事務在執行的過程中,不應該受到其它事務的干擾。

         持久性:事務一旦結束,數據持久化到數據庫。

問題:不考慮事務的隔離性,會產生什麼問題?

         髒讀:一個事務讀取到另一個事務的未提交數據

不可重複讀:一個事務讀取到另一個事務提交的數據(主要是指update),會導致兩次讀取的結果不一致。

虛讀(幻讀): 一個事務讀取到另一個事務提交的數據(主要是指insert),會導致兩次讀取結果不一致.

問題:對於上述問題如何解決?

         我們可以通過設置隔離級別來解決.

         READ_UNCOMMITED 讀取未提交,它引發所有的隔離問題

         READ_COMMITTED  讀已提交,阻止髒讀,可能發生不可重複讀與虛讀.

         REPEATABLE_READ 重複讀  阻止髒讀,不可重複讀 可能發生虛讀

SERIALIZABLE 串行化 解決所有問題 不允許兩個事務,同時操作一個目標數據。(效率低下)

 

ORACLE  默認的是事務隔離級別  READ_COMMITTED

MYSQL 默認的事務隔離級別  REPEATABLE_READ

Hibernate中設置事務隔離級別

hibernate.connection.isolation

它可取的值有 1 2 4 8

1代表的事務隔離級別爲READ UNCOMMITTED

2代表的事務隔離級別爲READ COMMITTED

4.代表的事務隔離級別爲 REPEATABLE READ

8代表的事務隔離級別爲 SERIALIZABLE

在hibernate.cfg.xml文件中配置

Hibernate中session管理

 Hibernate提供了三種管理session的方式:

  1. Session對象的生命週期與本地線程綁定(ThreadLocal)
  2. Session對象的生命週期與JTA事務綁定(分佈式事務管理)
  3. Hibernate委託程序來管理Session的生命週期

我們之前所使用的是第三種 ,通過程序獲取一個Session對象,使用它,最後session.close();

 

在實際開發中我們一般使用的是前兩種:

         主要介紹關於本地線程綁定Session。

         步驟:

1、需要在hibernate.cfg.xml文件配置。

2、在獲取session時不要再使用openSession而是使用getCurrentSession()方法。

關於getCurrentSession使用時的注意事項:

上述代碼執行後,會產生問題:

原因:使用getCurrentSession獲取的與線程綁定的session對象,在事務關閉時,session對象也會close,簡單說,就不需要我們在手動close。

Hibernate優化方案

HQL優化

1.使用參數綁定

         1.使用綁定參數的原因是讓數據庫一次解析SQL,對後續的重複請求可以使用用生成好的執行計劃,這樣做節省CPU時間和內存。

         2.避免SQL注入。

2.儘量少使用NOT

         如果where子句中包含not關鍵字,那麼執行時該字段的索引失效。

3.儘量使用where來替換having

Having在檢索出所有記錄後纔對結果集進行過濾,這個處理需要一定的開銷,而where子句限制記錄的數目,能減少這方面的開銷

4.減少對錶的查詢

         在含有子查詢的HQL中,儘量減少對錶的查詢,降低開銷

5.使用表的別名

當在HQL語句中連接多個表時,使用別名,提高程序閱讀性,並把別名前綴與每個列上,這樣一來,可以減少解析時間並減少列歧義引起的語法錯誤。

6.實體的更新與刪除

         在hibernate3以後支持hql的update與delete操作

        

一級緩存優化

一級緩存也叫做session緩存,在一個hibernate session有效,這級緩存的可干預性不強,大多於hibernate自動管理,但它提供清除緩存的方法,這在大批量增加(更新)操作是有效果的,例如,同時增加十萬條記錄,按常規進行,很可能會出現異常,這時可能需要手動清除一級緩存,session.evict以及session.clear.

檢索策略(抓取策略)

延遲加載

延遲加載 是hibernate爲提高程序執行的效率而提供的一種機制,即只有真正使用該對象的數據時纔會創建。

load方法採用的策略延遲加載.

get方法採用的策略立即加載。

檢索策略分爲兩種:

  1. 類級別檢索
  2. 關聯級別檢索

類級別檢索

類級別檢索是通過session直接檢索某一類對應的數據,例如

Customer c=session.load(Customer.class,1)

Session.createQuery(“from Order”)

類級別檢索策略分爲立即檢索與延遲檢索,默認是延遲檢索,類級別的檢索策略可以通過<class>元素的lazy屬性來設置 ,默認值是true。

在hbm配置文件中設置:

在類中使用註解

如果將lazy設置爲false,代表類級別檢索也使用立即檢索。這時load與get就一樣,都是立即檢索。

問題:如果對一個延遲代理對象進行初始化?

關聯級別檢索

         查詢到某個對象,獲得其關聯的對象或屬性,這種稱爲關聯級別檢索,例如

         c.getOrders().size()

         c.getName()

         對於關聯級別檢索我們就要研究其檢索策略(抓取策略)

檢索策略(抓取策略)

抓取策略介紹

 指的是查找到某個對象後,通過這個對象去查詢關聯對象的信息時的一種策略。

一對一 <one-to-one>

一對多(多對一) <set>下有<one-to-many>  <many-to-one>

多對多 <set>下有<many-to- many>

我們主要是在<set>與<many-to-one>或<one-to-one>上設置fetch  lazy

例如:查詢一個客戶,要關聯查詢它的訂單

客戶是一的一方,在客戶中有set集合來描述其訂單,在配置中我們是使用

<set>

         <one-to-many>

</set>..

可以在set標籤上設置兩個屬性  fetch   lazy

Fetch主要描述的是SQL語句的格式(例如是多條,子查詢,多表聯查

Lazy 控制SQL語句何時發送

例如:在查詢一個訂單時,要查詢客戶信息

<many-to-one> 或<one-to-one>

也可以設置fetch  lazy

Fetch主要描述的是SQL語句的格式(例如是多條,子查詢,多表聯查

Lazy 控制SQL語句何時發送

總結:

講解抓取策略

在兩方面設置

<set fetch=”” lazy=””>

<many-to-one fetch=”” lazy=””>

<one-to-one>

註解配置抓取策略

問題:如何使用註解來設置

在<setse>設置的fetch與lazy可以使用下面註解來描述

在<many-to-one>或<one-to-one>上如何設置 fetch與lazy

set上的fetch與lazy

set上的fetch與lazy它主要是用於設置關聯的集合信息的抓取策略。

Fetch可取值有:

  1. SELECT 多條簡單的sql   (默認值)
  2. JOIN 採用迫切左外連接
  3. SUBSELECT 將生成子查詢的SQL

lazy可取值有:

  1. TURE 延遲檢索   (默認值)
  2. FALSE 立即檢索
  3. EXTRA 加強延遲檢索(及其懶惰)

第一種組合:

會首先查詢客戶信息,當需要訂單信息時,纔會關聯查詢訂單信息。

第二種組合:

當查詢客戶信息時,就會將訂單信息也查詢,也就是說訂單信息沒有進行延遲。

第三種組合:

當查詢客戶信息時,不會查詢訂單信息,當需要訂單的個數時,也不會查詢訂單信息,

只會通過count來統計訂單個數。

當我們使用size(),contains()或isEmpty()方法時不會查詢訂單信息。

第四種組合:

如果fetch選擇的是join方案,那麼lazy它會失效。

生成SQl將採用的是迫切左外連接(left outer join fetch)

會立即查詢。

第五種組合:

會生成子查詢,但是我們在查詢訂單時採用的是延遲加載。

第六種組合:

會生成子查詢,在查詢客戶信息時,就會將訂單信息也查詢出來

第七種組合:

在查詢訂單時,只會根據情況來確定是否要訂單信息,如果不需要,例如我們

程序中size操作,那麼就會發出select count(*) from Order where c_customer_id=?

One的一方fetch與lazy

<set fetch lazy>它主要是設置在獲取到一的一方時,如果去查詢多的一方。

在<many-to-one>或<one-to-one>如果去查詢對方。

對於程序 就是在多的一方如何查詢一的主方信息

例如:獲取到一個訂單對象,要查詢客戶信息。

Fetch可取值:

         select 默認值,代表發送一條或多條簡單的select語句

         join  發送一條迫切左外連接

lazy可取值

         false 不採用延遲加載

         proxy 默認值 是否採用延遲,需要另一方的類級別延遲策略來決定

         no-proxy 不用研究

第一種組合:

注意:Customer的類級別延遲策略

當我們執行時,會首先發送一條sql只查詢訂單信息,客戶信息會延遲,只有真正需要客戶信息時,纔會發送sql來查詢客戶信息.

第二種組合

注意:Customer的類級別延遲策略

當查詢訂單時,就會將客戶信息也查詢到,原因是Customer它的類級別延遲爲false,也就是立即查詢。

第三種組合

當查詢訂單時,不會對客戶信息進行延遲,立即查詢客戶信息

第四種組合

如果fetch值爲join,那麼lazy失效。

會發送一條迫切左外連接來查詢,也就立即查詢。

批量抓取

我們在查詢多個對象的關聯對象時,可以採用批量抓取方式來對程序進行優化.

要想實現批量抓取:

可以在配置文件中 batch-size屬性來設置

可以使用註解 @BatchSize(size=4)

可以採用批量抓取來解決N+1問題.

查詢客戶,查詢訂單

可以在客戶配置文件中配置batch-size,是在<set>標籤上

查詢訂單,查詢客戶

訂單與客戶,客戶它是一個主表,訂單是一個從表。

在設置批量抓取時都是在主表中設置

在配置文件中在主表的<calss>標籤上設置batch-size

在註解使用中

注意:無論是根據哪一方來查詢別一方,在進行批量抓取時,都是在父方來設置 ,

         如果是要查詢子信息,那麼我們是在<set>上來設置batch-size,如果是從子方來查詢父方,

         也是在父方設置在<class>設置batch-size.
        

父與子區分:

         有外鍵的表是子(從)關聯方就是父(主)表

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章