Hibernate學習筆記(二)

Hibernate常用的配置文件


Hibernate配置文件之映射配置文件

 1. 映射文件,即Stu.hbm.xml的配置文件
    * <class>標籤     -- 用來將類與數據庫表建立映射關係
        * name          -- 類的全路徑
        * table         -- 表名.(類名與表名一致,那麼table屬性也可以省略)
        * catalog       -- 數據庫的名稱,基本上都會省略不寫

    * <id>標籤            -- 用來將類中的屬性與表中的主鍵建立映射,id標籤就是用來配置主鍵的。
        * name          -- 類中屬性名
        * column        -- 表中的字段名.(如果類中的屬性名與表中的字段名一致,那麼column可以省略.)
        * length        -- 字段的程度,如果數據庫已經創建好了,那麼length可以不寫。如果沒有創建好,生成表結構時,length最好指定。

    * <property>        -- 用來將類中的普通屬性與表中的字段建立映射.
        * name          -- 類中屬性名
        * column        -- 表中的字段名.(如果類中的屬性名與表中的字段名一致,那麼column可以省略.)
        * length        -- 數據長度
        * type          -- 數據類型(一般都不需要編寫,如果寫需要按着規則來編寫)
            * Hibernate的數據類型    type="string"
            * Java的數據類型     type="java.lang.String"
            * 數據庫字段的數據類型    <column name="name" sql-type="varchar"/>

Hibernate配置文件之核心配置文件

1. 核心配置文件的兩種方式
* 第一種方式是屬性文件的形式,即properties的配置文件
    * hibernate.properties
        * hibernate.connection.driver_class=com.mysql.jdbc.Driver
    * 缺點
        * 不能加載映射的配置文件,需要手動編寫代碼去加載

* 第二種方式是XML文件的形式,開發基本都會選擇這種方式
    * hibernate.cfg.xml
        * <property name="hibernate.connection.driver_class" >com.mysql.jdbc.Driver</property>
    * 優點
        * 格式比較清晰
        * 編寫有提示
        * 可以在該配置文件中加載映射的配置文件(最主要的)

2. 關於hibernate.cfg.xml的配置文件方式
* 必須有的配置
    * 數據庫連接信息:
        hibernate.connection.driver_class           -- 連接數據庫驅動程序
        hibernate.connection.url                    -- 連接數據庫URL
        hibernate.connection.username               -- 數據庫用戶名
        hibernate.connection.password               -- 數據庫密碼

    * 方言:
        hibernate.dialect                           -- 操作數據庫方言

* 可選的配置
    * hibernate.show_sql                            -- 顯示SQL
    * hibernate.format_sql                          -- 格式化SQL
    * hibernate.hbm2ddl.auto                        -- 通過映射轉成DDL語句
        * create                -- 每次都會創建一個新的表.---測試的時候
        * create-drop           -- 每次都會創建一個新的表,當執行結束之後,將創建的這個表刪除.---測試的時候
        * update                -- 如果有表,使用原來的表.沒有表,創建一個新的表.同時更新表結構.
        * validate              -- 如果有表,使用原來的表.同時校驗映射文件與表中字段是否一致如果不一致就會報錯.

* 加載映射
    * 如果XML方式:<mapping resource="cn/itcast/hibernate/domain/User.hbm.xml" />

Hibernate常用的接口和類


Configuration類和作用

1. Configuration類
    * Configuration對象用於配置並且啓動Hibernate。
    * Hibernate應用通過該對象來獲得對象-關係映射文件中的元數據,以及動態配置Hibernate的屬性,然後創建SessionFactory對象。

    * 簡單一句話:加載Hibernate的配置文件,可以獲取SessionFactory對象。

2. Configuration類的其他應用(瞭解)
    * 加載配置文件的種類,Hibernate支持xml和properties類型的配置文件,在開發中基本都使用XML配置文件的方式。
        * 如果採用的是properties的配置文件,那麼通過Configuration configuration = new Configuration();就可以假裝配置文件
            * 但是需要自己手動加載映射文件
            * 例如:config.addResource("cn/itcast/domain/Student.hbm.xml");

        * 如果採用的XML的配置文件,通過Configuration configuration = new Configuration().configure();加載配置文件

SessionFactory:重要

1. 是工廠類,是生成Session對象的工廠類
2. SessionFactory類的特點
    * 由Configuration通過加載配置文件創建該對象。
    * SessionFactory對象中保存了當前的數據庫配置信息和所有映射關係以及預定義的SQL語句。同時,SessionFactory還負責維護Hibernate的二級緩存。
        * 預定義SQL語句
            * 使用Configuration類創建了SessionFactory對象是,已經在SessionFacotry對象中緩存了一些SQL語句
            * 常見的SQL語句是增刪改查(通過主鍵來查詢)
            * 這樣做的目的是效率更高

    * 一個SessionFactory實例對應一個數據庫,應用從該對象中獲得Session實例。
    * SessionFactory是線程安全的,意味着它的一個實例可以被應用的多個線程共享。
    * SessionFactory是重量級的,意味着不能隨意創建或銷燬它的實例。如果只訪問一個數據庫,只需要創建一個SessionFactory實例,且在應用初始化的時候完成。
    * SessionFactory需要一個較大的緩存,用來存放預定義的SQL語句及實體的映射信息。另外可以配置一個緩存插件,這個插件被稱之爲Hibernate的二級緩存,被多線程所共享

3. 總結
    * 一般應用使用一個SessionFactory,最好是應用啓動時就完成初始化。

SessionFactory


Session接口

1. 概述
    * Session是在Hibernate中使用最頻繁的接口。也被稱之爲持久化管理器。它提供了和持久化有關的操作,比如添加、修改、刪除、加載和查詢實體對象
    * Session 是應用程序與數據庫之間交互操作的一個單線程對象,是 Hibernate 運作的中心
    * Session是線程不安全的
    * 所有持久化對象必須在 session 的管理下纔可以進行持久化操作
    * Session 對象有一個一級緩存,顯式執行 flush 之前,所有的持久化操作的數據都緩存在 session 對象處
    * 持久化類與 Session 關聯起來後就具有了持久化的能力

2. 特點
    * 不是線程安全的。應避免多個線程使用同一個Session實例
    * Session是輕量級的,它的創建和銷燬不會消耗太多的資源。應爲每次客戶請求分配獨立的Session實例
    * Session有一個緩存,被稱之爲Hibernate的一級緩存。每個Session實例都有自己的緩存

3. 常用的方法
    * save(obj)
    * delete(obj)  
    * get(Class,id)
    * update(obj)
    * saveOrUpdate(obj)                 -- 保存或者修改(如果沒有數據,保存數據。如果有,修改數據)
    * createQuery()                     -- HQL語句的查詢的方式

Transaction接口

1. Transaction是事務的接口
2. 常用的方法
    * commit()              -- 提交事務
    * rollback()            -- 回滾事務

3. 特點
    * Hibernate框架默認情況下事務不自動提交.需要手動提交事務
    * 如果沒有開啓事務,那麼每個Session的操作,都相當於一個獨立的事務

Hibernate的持久化類


什麼是持久化類


1. 持久化類:就是一個Java類(咱們編寫的JavaBean),這個Java類與表建立了映射關係就可以成爲是持久化類。
    * 持久化類 = JavaBean + xxx.hbm.xml

持久化類的編寫規則

1. 提供一個無參數 public訪問控制符的構造器              -- 底層需要進行反射.
2. 提供一個標識屬性,映射數據表主鍵字段                   -- 唯一標識OID.數據庫中通過主鍵.Java對象通過地址確定對象.持久化類通過唯一標識OID確定記錄
3. 所有屬性提供public訪問控制符的 set或者get 方法
4. 標識屬性應儘量使用基本數據類型的包裝類型

區分自然主鍵和代理主鍵

1. 創建表的時候
    * 自然主鍵:對象本身的一個屬性.創建一個人員表,每個人都有一個身份證號.(唯一的)使用身份證號作爲表的主鍵.自然主鍵.(開發中不會使用這種方式)
    * 代理主鍵:不是對象本身的一個屬性.創建一個人員表,爲每個人員單獨創建一個字段.用這個字段作爲主鍵.代理主鍵.(開發中推薦使用這種方式)

2. 創建表的時候儘量使用代理主鍵創建表

主鍵的生成策略

1. increment:適用於short,int,long作爲主鍵.不是使用的數據庫自動增長機制.
    * Hibernate中提供的一種增長機制.
        * 先進行查詢 :select max(id) from user;
        * 再進行插入 :獲得最大值+1作爲新的記錄的主鍵.

    * 問題:不能在集羣環境下或者有併發訪問的情況下使用.

2. identity:適用於short,int,long作爲主鍵。但是這個必須使用在有自動增長數據庫中.採用的是數據庫底層的自動增長機制.
    * 底層使用的是數據庫的自動增長(auto_increment).像Oracle數據庫沒有自動增長.

3. sequence:適用於short,int,long作爲主鍵.底層使用的是序列的增長方式.
    * Oracle數據庫底層沒有自動增長,想自動增長需要使用序列.

4. uuid:適用於char,varchar類型的作爲主鍵.
    * 使用隨機的字符串作爲主鍵.

5. native:本地策略.根據底層的數據庫不同,自動選擇適用於該種數據庫的生成策略.(short,int,long)
    * 如果底層使用的MySQL數據庫:相當於identity.
    * 如果底層使用Oracle數據庫:相當於sequence.

6. assigned:主鍵的生成不用Hibernate管理了.必須手動設置主鍵.

Hibernate持久化對象


持久化對象的狀態

1. Hibernate的持久化類
    * 持久化類:Java類與數據庫的某個表建立了映射關係.這個類就稱爲是持久化類.
        * 持久化類 = Java類 + hbm的配置文件

2. Hibernate的持久化類的狀態
    * Hibernate爲了管理持久化類:將持久化類分成了三個狀態
        * 瞬時態:Transient  Object
            * 沒有持久化標識OID, 沒有被納入到Session對象的管理.

        * 持久態:Persistent Object
            * 有持久化標識OID,已經被納入到Session對象的管理.

        * 脫管態:Detached Object
            * 有持久化標識OID,沒有被納入到Session對象的管理.

Hibernate持久化對象的狀態的轉換

1. 瞬時態  -- 沒有持久化標識OID, 沒有被納入到Session對象的管理
    * 獲得瞬時態的對象
        * User user = new User()
    * 瞬時態對象轉換持久態
        * save()/saveOrUpdate();
    * 瞬時態對象轉換成脫管態
        * user.setId(1)

2. 持久態  -- 有持久化標識OID,已經被納入到Session對象的管理
    * 獲得持久態的對象
        * get()/load();
    * 持久態轉換成瞬時態對象
        * delete();  --- 比較有爭議的,進入特殊的狀態(刪除態:Hibernate中不建議使用的)
    * 持久態對象轉成脫管態對象
        * session的close()/evict()/clear();

3. 脫管態  -- 有持久化標識OID,沒有被納入到Session對象的管理
    * 獲得託管態對象:不建議直接獲得脫管態的對象.
        * User user = new User();
        * user.setId(1);
    * 脫管態對象轉換成持久態對象
        * update();/saveOrUpdate()/lock();
    * 脫管態對象轉換成瞬時態對象
        * user.setId(null);

4. 注意:持久態對象有自動更新數據庫的能力!!!

三種狀態對象之間的轉換


Hibernate對象的一級緩存


Session對象的一級緩存(重點)

1. 什麼是緩存?
    * 其實就是一塊內存空間,將數據源(數據庫或者文件)中的數據存放到緩存中.再次獲取的時候 ,直接從緩存中獲取.可以提升程序的性能!

2. Hibernate框架提供了兩種緩存
    * 一級緩存  -- 自帶的不可卸載的.一級緩存的生命週期與session一致.一級緩存稱爲session級別的緩存.
    * 二級緩存  -- 默認沒有開啓,需要手動配置纔可以使用的.二級緩存可以在多個session中共享數據,二級緩存稱爲是sessionFactory級別的緩存.

3. Session對象的緩存概述
    * Session接口中,有一系列的java的集合,這些java集合構成了Session級別的緩存(一級緩存).將對象存入到一級緩存中,session沒有結束生命週期,那麼對象在session中存放着
    * 內存中包含Session實例 --> Session的緩存(一些集合) --> 集合中包含的是緩存對象!

4. 證明一級緩存的存在,編寫查詢的代碼即可證明
    * 在同一個Session對象中兩次查詢,可以證明使用了緩存

5. Hibernate框架是如何做到數據發生變化時進行同步操作的呢?
    * 使用get方法查詢User對象
    * 然後設置User對象的一個屬性,注意:沒有做update操作。發現,數據庫中的記錄也改變了。
    * 利用快照機制來完成的(SnapShot)

session的快照機制


控制Session的一級緩存(瞭解)

1. 學習Session接口中與一級緩存相關的方法
    * Session.clear()                       -- 清空緩存。
    * Session.evict(Object entity)          -- 從一級緩存中清除指定的實體對象。
    * Session.flush()                       -- 刷出緩存

Hibernate中的事務與併發


事務的相關概念(面試題)

1. 什麼是事務
    * 事務就是邏輯上的一組操作,組成事務的各個執行單元,操作要麼全都成功,要麼全都失敗.
    * 轉賬的例子:冠希給美美轉錢,扣錢,加錢。兩個操作組成了一個事情!

2. 事務的特性
    * 原子性   -- 事務不可分割.
    * 一致性   -- 事務執行的前後數據的完整性保持一致.
    * 隔離性   -- 一個事務執行的過程中,不應該受到其他的事務的干擾.
    * 持久性   -- 事務一旦提交,數據就永久保持到數據庫中.

3. 如果不考慮隔離性:引發一些讀的問題
    * 髒讀            -- 一個事務讀到了另一個事務未提交的數據.
    * 不可重複讀 -- 一個事務讀到了另一個事務已經提交的update數據,導致多次查詢結果不一致.
    * 虛讀            -- 一個事務讀到了另一個事務已經提交的insert數據,導致多次查詢結構不一致.

4. 通過設置數據庫的隔離級別來解決上述讀的問題
    * 未提交讀:以上的讀的問題都有可能發生.
    * 已提交讀:避免髒讀,但是不可重複讀,虛讀都有可能發生.
    * 可重複讀:避免髒讀,不可重複讀.但是虛讀是有可能發生.
    * 串行化:以上讀的情況都可以避免.

5. 如果想在Hibernate的框架中來設置隔離級別,需要在hibernate.cfg.xml的配置文件中通過標籤來配置
    * 通過:hibernate.connection.isolation = 4 來配置
    * 取值
        * 1—Read uncommitted isolation
        * 2—Read committed isolation
        * 4—Repeatable read isolation
        * 8—Serializable isolation

丟失更新的問題(面試題)

1. 如果不考慮隔離性,也會產生寫入數據的問題,這一類的問題叫丟失更新的問題。
2. 例如:兩個事務同時對某一條記錄做修改,就會引發丟失更新的問題。
    * A事務和B事務同時獲取到一條數據,同時再做修改
    * 如果A事務修改完成後,提交了事務
    * B事務修改完成後,不管是提交還是回滾,如果不做處理,都會對數據產生影響

3. 解決方案有兩種
    * 悲觀鎖
        * 採用的是數據庫提供的一種鎖機制,如果採用做了這種機制,在SQL語句的後面添加 for update 子句
            * 當A事務在操作該條記錄時,會把該條記錄鎖起來,其他事務是不能操作這條記錄的。
            * 只有當A事務提交後,鎖釋放了,其他事務才能操作該條記錄

    * 樂觀鎖
        * 採用版本號的機制來解決的。會給表結構添加一個字段version=0,默認值是0
            * 當A事務在操作完該條記錄,提交事務時,會先檢查版本號,如果發生版本號的值相同時,纔可以提交事務。同時會更新版本號version=1.
            * 當B事務操作完該條記錄時,提交事務時,會先檢查版本號,如果發現版本不同時,程序會出現錯誤。

4. 使用Hibernate框架解決丟失更新的問題
    * 悲觀鎖
        * 使用session.get(Customer.class, 1,LockMode.UPGRADE); 方法

    * 樂觀鎖
        * 1.在對應的JavaBean中添加一個屬性,名稱可以是任意的。例如:private Integer version; 提供get和set方法
        * 2.在映射的配置文件中,提供<version name="version"/>標籤即可。

悲觀鎖和樂觀鎖


綁定本地的Session

1. 之前在講JavaWEB的事務的時候,需要在業務層使用Connection來開啓事務,
    * 一種是通過參數的方式傳遞下去
    * 另一種是把Connection綁定到ThreadLocal對象中

2. 現在的Hibernate框架中,使用session對象開啓事務,所以需要來傳遞session對象,框架提供了ThreadLocal的方式
    * 需要在hibernate.cfg.xml的配置文件中提供配置
        * <property name="hibernate.current_session_context_class">thread</property>

    * 使用SessionFactory的getCurrentSession()方法,獲取當前的Session對象。並且該Session對象不用手動關閉,線程結束了,會自動關閉。
        public static Session getCurrentSession(){
            return factory.getCurrentSession();
        }

    * 注意:想使用getCurrentSession()方法,必須要先配置才能使用。

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