1. 程式人生 > >Hibernate入門三

Hibernate入門三

redis save .com system 問題 signed local getc 封裝數據

使用Hibernate最大的目的就是對數據庫進行crud操作。在講解之前,我們需要了解持久化以及持久化對象的三種狀態。

?

什麽是持久化

持久化就是把內存中的數據永久的存儲到數據庫中

?

什麽是持久化類

持久化類就是Java類與數據庫建立的一種映射關系,並把這個類稱做持久化類。實際上,就是一張數據表中的字段與類中的屬性字段相對象的類。

?

持久化類的編寫規範

1.需要提供無參數的構造方法
??因為Hibernate通過反射機制生成類的實例
2.需要私有屬性,並提供對應的get和set方法
??因為Hibernate底層會對獲取到的數據驚醒封裝
3.屬性盡量使用包裝類類型
?? 區分空和null

4.類中必須存在一個唯一標識 OID與表中的主鍵對應
?? Hibernate利用這個這個唯一標識來區分內存中是否是同一個持久化類
5.不要使用final修飾類
??因為Hibernate有加載延遲機制,這個機制會產生代理對象。代理對象是通過字節 碼增強技術來完成的,其實就是通過產生子類的方式,如果使用final修飾持久化類,這個機制就會失敗。加載延遲機制是一種優化的手段。

?

Hibernate主鍵生成策略

主鍵的類型

  1. 自然主鍵
    把具有業務含義的字段作為主鍵,稱為自然主鍵。比如,客戶的姓名(必須保證姓名不重復,唯一,非空),這類主鍵往往會因為業務的改變重新設計表,造成數據庫維護困難。
  2. 代理主鍵
    把具有非業務字段作為主鍵,稱為代理主鍵。通常是ID,類型是整數類型(比字符串節省空間)
  3. Hibernate提供了幾個內置主鍵生成策略
    1.increment:用於short int long類型。以自動增長的方式,每次增量是1。
    2.identity:采用底層數據庫本身提供的主鍵生成標識,前提是數據庫支持自動增長的類型。
    3.sequence:Hibernate根基底層序列生成標識符,前提是數據庫支持序列。
    4.native:根據底層數據庫生成能力來判斷生成identity、sequence、hilo中的一種。適合跨數據庫開發。
    5.uuid:采用128位uuid算法生成標識符
    6.assigned:由Java程序負責生成標識符。如果不指定id的generator屬性,默認使用該屬性。適合自然類型。

?

Hibernate持久化對象的三種狀態

  1. 瞬時態
    也稱為臨時態,托管態,實例是new出來的。不存在唯一標識OID,也沒有和Hibernate Session關聯
  2. 托管態
    也稱為離線態,遊離態。當某個持久態狀態的實例與session失去關聯的時候就變成為托管態。但是,托管態對象仍然存在唯一 標識OID,與數據庫中的數據存在關聯,只不過托管態對象發生改變的時候,Hibernate無法檢測到。
  3. 持久態
    對象存在OID,並且與Session關聯。值得註意的是,持久態對象在是事務還沒有提交之前變成持久態的。

下面通過列舉例子來說明上述內容

@Test
    public void demo() {

        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();

        // 瞬時態,此時沒有OID,也沒有與session關聯
        User user = new User(); 
        user.setUsername("robin");

        Serializable save = session.save(user); // 持久態

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

        // 托管態,此時session關閉,沒有與session關聯,但是有OID
        System.out.println(user);  
    }

技術分享圖片

轉換關系
?
瞬時態
1.瞬時態 -- 持久態
??調用save()或者saveOrUpdate()
2.瞬時態 -- 托管態
??為瞬時態添加 OID
?
持久態:可以從Session get() load()方法獲取,或者Query對象等
1.持久態 -- 瞬時態
??session.delete()刪除持久態化對象
2.持久態 -- 托管態
??session.evict()、clear()、close()方法。evict()用於清除一級緩存中的某一個對象,clear()用於清除一級緩存中的所有對象, close()關閉session,並且清除一級緩存。
?
托管態
1.托管套 -- 持久態
??執行update()、saveOrUpdate() lock()等
2,托管態 -- 瞬時態
??把對象的OID設置為null

?

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

依賴Hibernateu一級緩存

@Test
    public void demo() {
        Session session = null;
        Transaction transaction = null;
        try {
            session = HibernateUtil.getSession();
            transaction = session.beginTransaction();

            User user = session.get(User.class, 2);
            user.setUsername("Robin");
           // session.update(user); 這句話可以省略,因為持久態的對象會自動更新數據庫

            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
        }
    }
}

?

Hibernate一級緩存

緩存是計算機為了提高讀取速度而設計的。通常介於應用程序和永久性存儲介質之間。提高應用的運行能力,通常是內存。
?
Hibernate緩存分為一級緩存和二級緩存(redis替代),一級緩存是Hibernate內置緩存,不能刪除。
?
Hibernate一級緩存實際上就是session緩存。Session緩存是一個內存空間,存放相互管理的Java對象。在使用對象查找的時候,會使用OID在Hibernate一級緩存中進行查找,如果查找到了,就返回此對象,否則,就會去數據庫查找與之相同OID的對象。
?
只要session實例沒有結束生命周期,存放在它上面的緩存也不會消失。

    一級緩存的特點

    當應用程序調用Session的save()、update、saveOrUpdate()的時候,Session緩存中沒有相應的對象的時候,Hibernate會自動的從數據庫中提取對應的數據加載到一級緩存中

    當應用程序調用Session load()、get(),以及Query中的、list()、iterator()的時候,Hibernate首先會從以及緩存中尋找對象,如果存在則不需要去數據庫中查找。,如果沒有則從數據庫中獲取並加載到一級緩存中

    當調用Session.close()的時候,session緩存會被清空。

?

測試一級緩存

觀察控制臺輸出的SQL語句

@Test
    public void demo() {
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        /**
         * 查詢兩次
         */
        /**
         * 第一次執行你會查詢數據庫
         * 第二次查詢只會去緩存中尋找
         */
        User user = session.get(User.class, 1);
        User user1 = session.get(User.class, 1);

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

?

一級緩存內部結構

    Hibernate向一級緩存中存儲數據的時候,會拷貝一份數據放在Hibernate快照區,當使用事務提交之後,會根據OID比較一級緩存中的數據和快照區中的數據是否一致,如果不一致,則執行更新操作,並且同步快照區的數據,否則則不執行任何操作。

?

Hibernate對事務的控制

?

  • 什麽是事務?
    通常對數據庫的操作過程中,一項事務會有一條或者多條SQL語句,只有當所有的語句正常執行的時候,所有的操作才會正常完成。如果中間出現異常現象,那麽所有的語句執行都不成功。換句話說,對於一組操作,要麽全部成功,要麽全部失敗。
    ?
  • 事務的四個基本特性
    原子性 一致性 隔離行 持久性
    原子性:對事務的操作,要不全部成功,要麽全部失敗。
    一致性:事務完成的時候,必須使所有的數據保持一致。
    隔離性:一個事務不能被另外一個事務幹擾。
    持久性:一旦提交了事務,對數據庫進行了操作,所有的操作就不可逆。永久性的被改變。
    ?
  • 事務並發引發的問題
    臟讀 不可重復讀 幻讀(虛讀)
    臟讀:一個事務讀取到另一個未提交事務的數據
    不可重復讀:一個事務中讀取到另外一個事務已提交的update數據,造成同一個事務中多次讀讀取數據不一致
    幻讀:一個事務中讀取到另外一個事務已提交的insert數據,造成同一個事務中多次讀讀取數據不一致
    ?
  • 事務的隔離級別
    讀未提交(read uncommitted 1級):允許讀取還未提交的數據,會造成臟讀,不可重復讀,幻讀
    已提交讀(read committed 2級):允許在事務並發時,讀取已經提交的數據,可防止臟讀
    可重復讀(repeatable read 4級):對相同字段的多次讀取結果是一樣的,可以防止臟讀,不可重復讀
    幻讀(serializable 8級):提供嚴格的事務隔離,可防止臟讀,不可重復讀,幻讀

?

Hibernate事務管理

?

  • 設置事務隔離級別(在核心配置文件中配置)
    <property name="hibernate.connection.isolation">4</property>
  • 在業務層處理事務的方法
    1.在業務層中獲取session,把它傳遞給持久層
    2.使用ThreadLocal將業務層獲取到的session綁定到當前線程中去。然後到業務層獲取的時候獲取當前線程的session.

      <property name="hibernate.current_session_context_class">thread</property>
        sessionFactory.getCurrentSession()
        可以不需要關閉session,線程結束之後會自動關閉
    
        thread: Session對象的生命周期與本地線程綁定
        jta:Session對象的生命周期與JTA事務綁定
        managed:Hinernate委托程序來管理Session對象的生命周期

?

Hibernate其它的API

??

  • Query
  • Criteria
  • SQLQuery
    ?

    Query是面對對象的Hibernate查詢操作。通過session.createQuery(),傳遞一個HQL語句,獲取Query對象。

@Test
    public void demo() {
        Session session = null;
        Transaction transaction = null;
        try {
            session = HibernateUtil.getSession();
            transaction = session.beginTransaction();

            /**
             * 創建Query
             * 調用對象的方法
             */
            Query query = session.createQuery("from User");

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

            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
        }
    }

Criteria是一個完全面對對象,可擴展的條件查詢API,它不需要考慮數據庫底層的實現,以及SQL語句的編寫。它是Hibernate核心查詢對象,又稱為OBC(Object By Criteria)

@Test
    public void demo() {
        Session session = null;
        Transaction transaction = null;
        try {
            session = HibernateUtil.getSession();
            transaction = session.beginTransaction();

            /**
             * Criteria
             *  創建Criteria對象
             *  調用方法
             */
            Criteria criteria = session.createCriteria(User.class);
            List<User> list = criteria.list();
            for (User user : list) {
                System.out.println(user);
            }
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
        }
    }

SQLQuery用來接收SQL語句,需要我們手動封裝數據

@Test
    public void demo03() {
        Session session = null;
        Transaction transaction = null;
        try {
            session = HibernateUtil.getSession();
            transaction = session.beginTransaction();

            /**
             * 對象
             * 調用方法
             */
            String sql = "select * from `tb_user`";
            SQLQuery sqlQuery = session.createSQLQuery(sql);

            sqlQuery.addEntity(User.class);

            List<User> list = sqlQuery.list();

//            List<Object[]> list = sqlQuery.list();
//            for (Object[] user : list) {
//                System.out.println(Arrays.toString(user));
//            }

            for (User user : list) {
                System.out.println(user);
            }

            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
        }
    }

Hibernate入門三