Hibernate

Hibernate

Hibernate應用在dao層

在dao層路面對數據庫進行crud操作的,使用hibernate實現,hibernate在底層代碼就是jdbc,hibernate對jdbc就行封裝,使用hibernate好處,就是不需要寫複雜的jdbc代碼
hebernate是輕量級的框架

orm思想:

讓實體類與表進行一一對應

hibernate本身沒有支持日誌的jar包,所有需要其他的jar包

log4j
slf4j-api
alf4j-log4j

建實體類

hibernate要求實體類有一個屬性唯一的set,get方法

配置實體類和數據庫表一一對應關係

使用配置文件實現映射關係

映射文件名稱和位置沒有固定要求

建議在實體類所在包中(.hbm.xml)

首先引入約束(dtd)

引入mapping.dtd約束

創建hibernate的核心配置文件

核心配置文件格式xml,核心配置文件名稱和位置固定的
位置:src下面
名稱: hibernate.cfg.xml
引入config.dtd約束

hibernate操作過程中,只會加載核心配置文件,其他配置文件不會加載

第一部分,配置數據庫信息

第二部分,配置hibernate信息

第三部分,將映射文件放到核心配置文件中

實現添加操作

第一步,加載hibernate核心配置文件

第二步,創建SessionFactory對象

第三步,使用SessionFactory創建Session對象

第四步,開啓事務

第五步,寫具體crud操作

第六步,提交事務

第七步,關閉資源

//加載hibernate核心配置文件
Configuration configuration = new Configuration();
configuration.configure();
//讀取hibernate核心配置文件內容,創建sessionFactory
//在過程中,根據映射關係,在配置數據庫裏把表創建
SessionFactory sessionFactory = configuration.buildSessionFactory();
//創建session對象
//類似於連接
Session session = sessionFactory.openSession();
//開啓事務
Transaction tx = session.beginTransaction();
//寫具體crud操作
User user = new User();
user.setUsername("劉政杉");
user.setPassword("53767");
user.setAddress("北京");
session.save(user);
//提交事務
tx.commit();
//關閉資源
session.close();
sessionFactory.close();

Hibernate配置文件詳解

hibernate映射配置文件 .hbm.xml

1.映射配置文件名稱和位置沒有固定要求

2.映射配置文件中,標籤name屬性值寫實體類相關內容

class標籤name屬性值實體類全路徑
id標籤property標籤name屬性值 實體類屬性名稱

3.id標籤和property標籤,column屬性可以省略

4.peoperty標籤type屬性,設置生成表字段的類型,自動對應類型

hibernate核心配置文件

1.配置寫位置要求


2.配置三部分要求

數據庫部分必須
hibernate部分可選的
映射文件必須

3.核心配置文件和位置固定的

位置:src下面
名稱:hibernate.cfg.xml

session

1.session類似於jdbc中的connection
2.調用session裏面不同方法實現crud操作
3.session對象單線程對象

transaction

1.事務對象
開啓事務
Transaction tx=session.beginTransaction();
2.事務提交和回滾
tx.commit()
tx.rollback()
3.事務四個特性:
原子性,一致性,隔離性,持久性

1.實體類編寫規則

實體類裏面屬性私有
私有屬性使用public的set和get方法
要求實體類有一個唯一值(一般id值)
實體類屬性建議不適用基本數據類型,使用其包裝類
基本數據類型無法表示“空,無”

2.hibernate主鍵生成策略

hibernate要求實體類裏有一個屬性作爲唯一值,作爲唯一值,主鍵可以不同生成策略
hibernate主鍵生成策略有很多值
<generator class="native"/>
native(Integer ),uuid(String)

3.實體類操作

crud操作

根據id查詢
調用session裏面的get方法
session.get(實體類.class,id值)

修改操作
session.update(實例)
執行過程,到user對象裏找到uid,根據uid進行修改

刪除
session.delete(實例)
執行過程,到user對象裏找到uid,根據uid進行刪除

實體類對象狀態

瞬時態
對象裏面沒有id值,對象與session沒有關聯
添加操作時

持久態
對象裏面有id值,對象與session關聯
根據id查詢

託管態
對象有id值,對象與session沒關聯
刪除時

saveOrUpdate()
就是根據對象狀態不同進行的操作
當實體類對象爲瞬時態時進行添加操作
當實體類爲託管態,持久態 進行修改操作

4.hibernate的一級緩存

什麼是緩存?

數據庫存到內存裏面。數據存到數據庫裏面,數據庫本身是文件系統,通過流方式操作文件。

hibernate緩存特點:

hibernate的一級緩存默認是打開的
hibernate的一級緩存使用範圍是session範圍,從session創建到關閉
hibernate的一級緩存中存儲數據必須持久態數據

第二類hibernate的二級緩存:
目前不適用,替代技術redis
二級緩存默認不是打開的,需要配置
二級緩存使用範圍,是sessinFactory範圍

一級緩存流程:

首先查詢一級緩存,如果沒有發現數據,就會去查詢數據,返回對象(持久態對象)然後,把持久太對象存放到一級緩存中。這裏注意,一級緩存中存放的不是對象,僅僅是鍵值。如果發現一級緩存中有相同的數據,直接返回。根據主鍵查詢,然後將數據裝配成對象返回。

hibernate一級緩存特性:
持久態自動更新數據庫

1.User user= session.get(User.class,7);

2.user.setUsernaem("hanmeimei");
一句查詢到數據後,把user持久態放到一級緩存中以及其對應的快照區中。二句重新設置username時會自動更新到一級緩存中,而不會修改快照區。
最後提交事務時,數據庫會比較緩存內容與快照區內容是否相同,如果不相同,就把一級緩存中內容更新到數據庫中。

5.hibernate的事務操作

1.什麼是事務

對於數據庫的操作

2.事務特性

原子性:一個事務要被完全的無二義性的做完或者撤銷
一致性:一個事務應該把系統從一個一致性換到另一個一致狀態
隔離性:每個事務獨立執行
持久性:被完成的事務的效果應該是持久的

3.不考慮隔離性產生讀問題

髒讀:A事務讀取到B事務中未提交的數據
不可重複讀:A事務讀取到了B事務中已提交的數據
虛讀:A事務中讀取B事務已提交的新插入的數據

4.解決讀問題

(1)設置隔離級別
mysql默認隔離級別:
repeatable read

<property name="hibernate.connection.isolation">4</property>

事務代碼規則寫法:
代碼結構

try{
    開啓事務
    提交事務
}catch{
    回滾事務
}finally{
    關閉
}

如何保證session一定是單線程?

與本地線程綁定
底層實現threadLocal,
獲取與本地線程綁定:
在hibernate核心配置文件中配置

<property name="hibernate.current_session_context_class">thread</preperty>
調用sessionFactory裏面的方法得到
    public static Session getSessionobject(){
        return sessionFactory.getCurrentSession();
    }

獲取與本地線程綁定session時候,關閉session,會報錯,不需要手動關閉

6.hibernate其他的api

Query對象
使用query對象,不需要寫sql語句,但是需要寫hql語句。
sql操作表和表字段
hql操作實體類和屬性

查詢所有hql語句:
from 實體類名稱

query對象使用
1.創建query對象
Query query = session.createQuery("from User");
List<User> list = query.list();
2.調用query對象裏面的方法得到結果



Criteira對象
不需要寫語句,直接調用方法
1.創建criteria對象
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.list();
2.調用方法得到結果



SQLQuery對象
使用hibernate時候,調用底層sql實現

創建對象,調用對象方法得到結果
SQLQuery sqlQuery = session.createSQLQuery("sql語言");
List list = sqlQuery.list();
默認返回數組形式

怎樣返回對象形式?
SQLQuery sqlQuery = session.createSQLQuery("sql語言");
sqlQuery.addEntity(User.class);
List<User> list = sqlQuery.list(); 

表與表之間關係回顧

1.一對多

在多的那一方創建字段作爲外鍵,只想一的那一方的主鍵

2.多對多

創建第三張表

hibernate一對多操作

1.一對多映射配置

hibernate要求使用集合表示多的數據,使用set集合,在實體類裏面表示
private Set setUser = new HashSet();
寫在Customer映射配置文件之後,在客戶映射文件中,表示所有聯繫人。

<!-- 在客戶映射文件中,表示所有聯繫人
使用set標籤表示所有聯繫人
set標籤裏面有name屬性,屬性值寫在客戶實體類裏面表示聯繫人的set集合名稱
 -->
<set name="setLinkMan">
<!-- 一對多建表,有外鍵
hibernate機制:雙向維護外鍵,在一和多那一方都配置外鍵
column屬性值:外鍵名稱
-->
<key column="cid"></key>
<!-- 客戶所有的聯繫人,class裏面寫聯繫人實體類全路徑-->
<one-to-many class=""/>
</set>

在聯繫人中表示所屬客戶

<!-- name:因爲在聯繫人實體類使用customer對象表示,寫customer名稱
class:customer全路徑
column:外鍵名稱,與之前在客戶中配置的外鍵一樣
-->
<many-to-one name="customer" class=" " column=""/>

2.一對多級聯保存

設置級聯
在客戶映射文件裏面,set標籤進行配置

<set name="setLinkMan" cascade="save-update">

第二步,創建客戶和聯繫人對象,只需要把聯繫人放到客戶裏面就可以了,最終只需要保存客戶

3.一對多級聯刪除

<set name="setLinkMan" cascade="save-update,delete">

4.inverse屬性

在做級聯更新時,因爲hibernate外鍵雙向維護特性,所以會引起兩次update
解決:一對多裏面,讓其中一方放棄外鍵的維護
具體做法:
set標籤上inverse屬性
inverse=”false”
false不放棄關係維護,
true放棄關係維護

hibernate多對多操作

多對多,兩方使用set
1.多對多映射配置

<!-- 在用戶裏面表示所有角色,使用set標籤
name屬性,角色set集合名稱
table屬性,第三張表名稱 
-->
<set name= "setRole" table="user_role">
    <!-- key標籤裏面配置
    配置當前映射文件在第三張表外鍵名稱
    -->
    <key column="userid"></key>
    <!--class,實體類全路徑
    column,另一個實體類在第三張表外鍵名稱
    -->
    <many-to-many class=" " column="另一個實體類在第三張表名稱"></many-to-many>
</set>

在對應的映射配置中,做相同的配置,只不過改成相應的值

2.多對多級聯保存

3.多對多級聯刪除

4.維護第三張表

hibernate查詢

1 hibernate的查詢方式

  1. 對象導航查詢
    根據id查詢某個客戶,在查詢這個客戶裏面所有聯繫人
  2. oid查詢
    根據id查詢某一條記錄,返回對象
  3. hql查詢
    Query對象,寫hql語句實現查詢
    hql hibernate query language
    hibernate提供一種查詢語言,sql操作數據表和字段,hql操作實體類和屬性

使用hql查詢時
創建Query對象,寫hql語句
調用query對象裏面的方法得到結果

  1. 查詢所有

    from 實體類名稱
    
  2. 條件查詢

    from 實體類名稱 where 實體類屬性名稱=? and 實體類屬性名稱=? 
    from 實體類名稱 where 實體類屬性名稱 like ?
    
    創建完query後,要設置條價值,即向?裏面添加值
    setParameter方法兩個參數
    第一個參數,int類型是?位置,?位置從0開始
    第二個參數,具體參數值
    query.setParameter(0,"baidu");
    
  3. 排序查詢

    from 實體類名稱 order by 實體類屬性名稱 asc/desc
    (升序/降序)
    
  4. 分頁查詢

    在mysql 中實現分頁查詢語句:
    select * from 表名 limit 0,3
    0:起始位置
    3:每頁顯示數量
    
    在hql中實現分頁,不能寫limit,因爲limit是MySQL的關鍵字,hibernate的query封裝兩個方法實現分頁操作
    Query query = session.createQuery("from Customer");
    設置分頁數據
    設置開始位置
    query.setFirstResult(0);
    設置每頁記錄數
    query.setMaxResults(3);
    
  5. 投影查詢

    什麼是投影查詢?
    查詢的不是所有字段值,而是部分字段的值
    
    select 實體類屬性名稱1,實體類屬性名稱1 from 實體類名稱
    seslet後面不能寫*,不支持的
    
  6. 聚集函數使用

    query對象裏面有方法,直接返回對象形式
    query.uniqueResult();
    count sum avg max min
    
  7. qbc查詢

    使用hql查詢需要寫hql語句實現,但是使用qbc時候,不需要寫語句,直接調用方法
    使用qbc時候,操作實體類和屬性
    使用qbc,使用Criteria對象實現
    Criteria對象
    Criteria criteria = session.createCriteria(實體類.class);
    
    1. 查詢所有

      criteria.list() 
      
    2. 條件查詢

          調用Restrictions裏面靜態方法,裏面方法很多,eq意味等於
          criteria.add(Restrictions.eq(實體類屬性名,值)); 
          會查找表中字段等於該值的並返回,依舊使用list方法
      
    3. 排序查詢

          criteria.addOrder(Order.asc/desc(實體類屬性名))
      
    4. 分頁查詢

          cirteria.setFirstResult(0)
          criteria.setMaxResults(3)
          開始位置 = (當前頁-1)* 每頁記錄數 
      
    5. 統計查詢

          criteria.setProjection(Projections.rowCount())
      
    6. 離線查詢

          開始時候不直接從session創建critirea
          DetachedCriteria detachedcriteria = DetachedCriteria.forClass(實體類.class);
          //最終執行時才需要session
          Criteria criteria = detachedCriteria.getExecutableCriteria(session)
      

爲什麼離線查詢?

servlet --> service --> dao
爲了不在dao中創建,並且拼接條件,可以使用離線查詢

本地sql查詢

SQLQuery對象,使用普通sql實現查詢

對象導航查詢

mysql中多表查詢

內連接查詢

select * from customer c,linkman l where c.cid = l.cid
select * from customer c inner join linkman l on c.cid = l.cid

左外連接

左邊表所有數據,右邊表關聯數據,沒有顯示null
select * from customer c left outer join linkman l on c.cid = l.cid

右外連接

select * from customer c right outer join linkman l on c.cid = l.cid

hql 中多表查詢

內連接

from Customer c inner join c.setLinkMan 
setLinkMan是customer中linkman的set集合
返回以數組形式

迫切內連接

迫切內連接和內連接底層實現是一樣的
區別:使用內連接返回list中每部分是數組,迫切內連接返回list每部分是對象
from Customer c inner join fetch c.setLinkMans

左外連接

from Customer c left outer join c.setLinkMan

迫切左外連接

from Customer c left outer join fetch c.setLinkMan

左外連接list中返回每部分是數組,迫切左外連接返回的是對象

右外連接

from Customer c right outer join c.setLinkMans

hiernnate 檢索策略

檢索策略的概念

hibernate檢索策略分爲兩類

1.立即查詢,根據id查詢,調用get方法,一調用get方法馬上發送語句查詢數據庫
2.延遲查詢,根據id查詢,還有load方法,調用load方法不會馬上發送語句查詢數據庫,只有用得到對象裏面的值纔會發送語句查詢數據庫,返回的對象裏面只有id值

延遲查詢分成兩類

1.類級別延遲
根據id查詢返回實體類對象,調用load方法不會馬上發送語句
2.關聯級別延遲
查詢某個客戶,再查詢這個客戶的所有聯繫人(這裏涉及外鍵),查詢客戶所有聯繫人的過程是否需要延遲

關聯級別延遲操作

1在映射文件中進行配置
根據客戶得到所有聯繫人,在客戶映射文件中配置

fetch:select 默認
lazy:
true 延遲(默認)
false 不延遲
extra 極其延遲,絕不多給

批量抓取:

查詢所有客戶,返回list集合,遍歷list集合,得到每個客戶,得到每個客戶的所有聯繫人
返回list中,發送多條語句,開銷大

優化:在客戶的映射文件中,set標籤進行配置
batch-size=”值”
值越大發送語句越少效率越高

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