[ Hibernate ] Hibernate 的主鍵生成策略、一級緩存以及事務管理(2)

1.持久化類的編寫規則

  • 對持久化類提供一個無參的構造方法 底層:反射生成實例
  • 屬性需要私有,提供public 的set和get方法 :Hibernate 中獲取,設置對象的值。
  • 對持久化類提供一個唯一標識的 OID 與數據庫主鍵對應 :java中通過對象地址區分是否是同一對象,數據庫中通過主鍵確認是否是同一個記錄,在hibernate中通過持久化類的OID的屬性區分是否是同一對象。
  • 持久化類中的屬性儘量使用包裝類屬性,包裝類型默認值爲null,基本數據類型默認值爲0,有歧義。
  • 持久化類不要使用final修飾 :延遲加載本來就是Hibernate 的一種優化手段,返回的是一個代理對象(javassist,可以對沒有實現接口的類產生代理—是用來非常底層字節碼增強技術,繼承這個類進行代理)。如果類被final 修飾不能被繼承了,就不能產生代理對象,延遲加載也就失效,此時的get 方法和load方法 一致。

2.主鍵生成策略

2.1主鍵的分類

2.1.1自然主鍵

  • 主鍵本身就是表中的一個字段(實體中的一個具體的屬性)
  • 創建一個人員表,人員都會有一個身份證號(唯一不可重複),人員的身份證號作爲主鍵,這種主鍵爲自然主鍵。

2.1.2代理主鍵(儘量使用)

  • 主鍵的本身不是表中必須的一個字段(不是實體類的牧歌具體的屬性)
    • 創建一個人員表,沒有使用人員中的身份證號,用了一個與這個表不相關的字段ID(PNO),這種主鍵就是代理主鍵。
  • 在實際開發中,儘量使用主鍵。、
    • 一旦主鍵參與到業務邏輯中,後期可能要修改源代碼。
    • 好的程序設計滿足OCP 原則:對程序的擴展是open的,對修改源碼是close的。

2.1.3主鍵生成策略

2.1.3.1 Hibernate 的主鍵生成策略

  • 在實際開發中一般不容許用戶手動設置主鍵,一般將主鍵交給數據庫,手動編寫程序進行設置,在Hibernate中爲減少程序編寫,提供了很多種主鍵的生成策略。
<hibernate-mapping>
    <!--建立類與表的影射-->
    <!--當類名與表名同名時,可省略表名的映射-->
    <class name="com.sunlong.hibernate01.domain.Custom" table="cst_customer">
        <!--建立類中的屬性與表中的主鍵對應-->
        <id name="cust_id" column="cust_id">
            <!--主鍵的生成策略-->
            <generator class="native"/>
        </id>
</hibernate-mapping>
  • increment
    Hibernate 中提供的自動增長機制,適用 short、int、long類型的主鍵,在單線程中使用。
  • identity
    適用short、int、long類型的主鍵,使用的是數據庫底層的自動增強機制。適用於有自動增器機制數據庫(MySQL、MSSQL),Oracle 沒有自增長機制。
  • sequence
    適用short、int、long類型的主鍵,採用的是序列的方式。(Oracle支持序列)MySQL 不能使用。
  • uuid
    適用於字符串類型主鍵。使用Hibernate 中的隨機方式生成字符串主鍵。
  • native
    本地策略,根據數據庫的能力選擇 identity、sequence。
  • assigned
    Hibernate 放棄外鍵的管理,需要通過手動編寫程序或者用戶自己設置。
  • foreign
    外部的,一對一的一種關聯映射的情況下使用。

2.2 持久化類的三種狀態

  • Hibernate 是持久層框架,通過持久化類完成ORM操作。Hibernate 爲了更好的管理持久化類,將持久化類分爲三種狀態。 持久化類 = java類 + 映射。

2.2.1 瞬時態

  • 這種對象沒有唯一的標識OID ,沒有被session 管理,稱爲瞬時態對象。

  • 瞬時態對象

  • 獲得
    Customer c = new Custonmer();

  • 狀態轉化

    • 瞬時—>持久
      save() saveOrUpdate()
    • 瞬時—>脫管

2.2.2持久態*

  • 這種對象有唯一的標識OID ,被session管理,稱爲持久態對象。
    • 可以自動更新到數據庫。
    • 獲得
      get() load() find() iterte()
      Customer c = session.get(Custonmer.class,1L);
  • 狀態轉化
    • 持久—>瞬時
      -delete()
    • 持久—>脫管
      -close() clear() evict()
  • 獲得
    Custonmer c = new Constmer();
    c.setCust_id(1L);
  • 狀態轉化
    • 脫管—>持久
      update() saveOrUpdate()
    • 脫管—>瞬時
      customer.setCust_id(null);

2.2.3 脫管態

  • 這種對象有唯一的標識OID,沒有被session管理,稱爲脫管態對象。

2.2.4 持久態對象可以自動更新數據庫

    @Test
    //修改操作
    public void demo03() {
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();

        //直接創建對象進行修改
        /*Custom custom = new Custom();
        custom.setCust_id( 1L );
        custom.setCust_name( "悟空" );
        session.update( custom );*/

        //先查詢,在修改(推薦)
        Custom custom1 = session.get( Custom.class, 1L );
        custom1.setCust_name( "八戒" );
        //持久化對象可以自動更新數據庫數據,如果更新數據和數據庫信息一樣,那就只進行查詢,不進行更新語句操作
        //一級緩存
        //session.update( custom1 );//不寫也更新

        transaction.commit();
        session.close();
    }

2.3 Hibernate 的一級緩存

2.3.1 緩存概述

2.3.1.1 什麼是緩存
  • 是一種優化方式,將數據存入到內存中,使用的時候直接從緩存中獲取,不用通過存儲源。

2.3.2 Hibernate 的緩存

2.3.2.1 Hibernate 的一級緩存
  • Hibernate 框架中提供了優化手段:緩存、抓取策略。
  • Hibernate 提供了兩種緩存機制:一級緩存 二級緩存
  • Hibernate 的一級緩存:稱爲session緩存
2.3.2.2 一級緩存證明
    @Test
    public void demo01() {
        /*
         * 一級緩存
         * */
        Configuration cfg = new Configuration().configure( "com/sunlong/hibernate02/hibernate.cfg.xml" );
        SessionFactory sessionFactory = cfg.buildSessionFactory();
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        Customer customer = session.get( Customer.class, 2L );

        System.out.println( customer );

        //清空所有緩存,控制檯打印兩次查詢語句,否則第二次查詢同一對象,將會從一級緩存中獲取
        //session.clear();

        //清空指定緩存
        session.evict( customer );

        Customer customer1 = session.get( Customer.class, 2L );
        System.out.println( customer1 );

        transaction.commit();
    }

2.4 Hibernate 的事務管理

2.4.1 事務回顧

2.4.1.1什麼是事務
  • 事務:邏輯上的一組操作,組成這組操作的各個邏輯單元要麼成功要麼失敗。
2.4.1.2事物特性
  • 原子性:事務不可分割
  • 一致性:事務執行的前後,數據的完整性保持一致
  • 隔離性:一個事務執行過程中,不應該是受到其他事務的干預。
  • 持久性:事務執行完成後,數據就持久到數據庫中。
2.4.1.3 如果不考慮隔離性,引發安全性問題
  • 讀問題
    • 髒讀:一個事務讀到另一個事務未提交的事務.
    • 不可重複讀:一個事務讀到另一個事務已經提交的update數據,導致在前一個事務對此查詢的結果不一致。
    • 幻讀:一個事務讀到另一個事務已經提交的insert 數據,導致在前一個事務多次查詢結果不一致。
  • 寫問題
    • 引發兩類丟失更新
2.4.1.4 讀問題的解決
  • 設置事物的隔離級別
    • 未提交讀 :以上讀問題都會發生
    • 讀已提交 :解決髒讀,但是不可重複讀和虛讀有可能發生
    • 可重複讀 ;解決髒讀和不可重複讀,但是幻讀有可能發生
    • 可串行化 :解決所有讀問題

2.4.2 Hibernate 中設置事務的隔離級別

  • 1 :讀未提交
  • 2 :讀已提交
  • 4 :可重複讀
  • 8 :可串行化
<!--設置事務隔離級別-->
<property name="hibernate.connection.isolation">4</property>

2.4.3 Service 事務管理

2.4.3.1 Hibernate 解決service 的事務管理
  • 事務管理的方式
    <1> 可以在業務層獲取到 Session ,並將 Session 作爲參數傳遞到 DAO。
    <2> (最優方案) 可以使用 ThreadLocal 將業務層獲取的 Session 綁定到當前線程中,然後在 DAO 中獲取 Session 的時候,都從當前線程中獲取。
    -Hibernate 提供 sessionFactory.getCurrentSession() 創建一個 session 和 ThreadLocal 綁定方法。
<!--配置當前線程綁定的Session-->
<property name="hibernate.current_session_context_class">thread</property>
  • 配置成功後即可使用 SessionFactory的getCurrentSession() 方法

2.5 Hibernate 的其他API

2.5.1 Query (HQL)

  • Query 代表面向對象的一個 Hibernate 查詢操作。在 Hibernate 中,通常使用 session.createQuery() 方法接收一個 HQL 語句,然後調用 Query 的 list() 或 uniqueResult() 方法執行查詢。所謂的HQL 是 Hibernate Query Language 的縮寫,其語法很像SQL 語句,但它是完全面向對象的。
//Query
public void demo02() {
    Session session = HibernateUtils.getCurrentSession();
    Transaction transaction = session.beginTransaction();

    //簡單查詢
    //String hql = "from Customer";
    //條件查詢
    //String hql = "from Customer where cust_name like ?";
    //分頁查詢
    String hql = "from Customer";
    Query query = session.createQuery( hql );

    //設置分頁
    query.setFirstResult( 3 );
    query.setMaxResults( 3 );
    //以下兩種設置佔位符的方式都可以
    //query.setParameter( 0 ,"孫%");
    //query.setString( 0,"孫%" );

    List<Customer> list = query.list();
    for (Customer customer : list) {
        System.out.println( customer );
    }

    transaction.commit();
}

2.5.2 Criteria :QBC (Query By Criteria)

  • 更加面向對象的一種方式查詢
  • 通過session獲得 session.createCriteria()
//Criteria更加面向對象的一種方式查詢
public void demo03() {
    Session session = HibernateUtils.getCurrentSession();
    Transaction transaction = session.beginTransaction();

    //查詢所有數據
    Criteria criteria = session.createCriteria( Customer.class );

    //條件查詢
    criteria.add( Restrictions.like( "cust_name", "孫%" ) );

    //分頁查詢
    criteria.setFirstResult( 3 );
    criteria.setMaxResults( 3 );

    List<Customer> list = criteria.list();
    for (Customer customer : list) {
        System.out.println( customer );
    }

    transaction.commit();
}

2.5.3 SQLQuery

  • SQLQuery 用於接收SQL ,在特別複雜的情況下使用,一般建議使用以上兩種。

  • 以上簡單介紹了三種檢索方式,後續會在專門章節詳細介紹。

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