溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Hibernate入門三

發(fā)布時間:2020-04-05 09:19:57 來源:網(wǎng)絡(luò) 閱讀:523 作者:小咴 欄目:開發(fā)技術(shù)
    使用Hibernate最大的目的就是對數(shù)據(jù)庫進(jìn)行crud操作。在講解之前,我們需要了解持久化以及持久化對象的三種狀態(tài)。

?

什么是持久化

持久化就是把內(nèi)存中的數(shù)據(jù)永久的存儲到數(shù)據(jù)庫中

?

什么是持久化類

持久化類就是Java類與數(shù)據(jù)庫建立的一種映射關(guān)系,并把這個類稱做持久化類。實(shí)際上,就是一張數(shù)據(jù)表中的字段與類中的屬性字段相對象的類。

?

持久化類的編寫規(guī)范

1.需要提供無參數(shù)的構(gòu)造方法
??因?yàn)镠ibernate通過反射機(jī)制生成類的實(shí)例
2.需要私有屬性,并提供對應(yīng)的get和set方法
??因?yàn)镠ibernate底層會對獲取到的數(shù)據(jù)驚醒封裝
3.屬性盡量使用包裝類類型
?? 區(qū)分空和null
4.類中必須存在一個唯一標(biāo)識 OID與表中的主鍵對應(yīng)
?? Hibernate利用這個這個唯一標(biāo)識來區(qū)分內(nèi)存中是否是同一個持久化類
5.不要使用final修飾類
??因?yàn)镠ibernate有加載延遲機(jī)制,這個機(jī)制會產(chǎn)生代理對象。代理對象是通過字節(jié) 碼增強(qiáng)技術(shù)來完成的,其實(shí)就是通過產(chǎn)生子類的方式,如果使用final修飾持久化類,這個機(jī)制就會失敗。加載延遲機(jī)制是一種優(yōu)化的手段。

?

Hibernate主鍵生成策略

主鍵的類型

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

?

Hibernate持久化對象的三種狀態(tài)

  1. 瞬時態(tài)
    也稱為臨時態(tài),托管態(tài),實(shí)例是new出來的。不存在唯一標(biāo)識OID,也沒有和Hibernate Session關(guān)聯(lián)
  2. 托管態(tài)
    也稱為離線態(tài),游離態(tài)。當(dāng)某個持久態(tài)狀態(tài)的實(shí)例與session失去關(guān)聯(lián)的時候就變成為托管態(tài)。但是,托管態(tài)對象仍然存在唯一 標(biāo)識OID,與數(shù)據(jù)庫中的數(shù)據(jù)存在關(guān)聯(lián),只不過托管態(tài)對象發(fā)生改變的時候,Hibernate無法檢測到。
  3. 持久態(tài)
    對象存在OID,并且與Session關(guān)聯(lián)。值得注意的是,持久態(tài)對象在是事務(wù)還沒有提交之前變成持久態(tài)的。

下面通過列舉例子來說明上述內(nèi)容

@Test
    public void demo() {

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

        // 瞬時態(tài),此時沒有OID,也沒有與session關(guān)聯(lián)
        User user = new User(); 
        user.setUsername("robin");

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

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

        // 托管態(tài),此時session關(guān)閉,沒有與session關(guān)聯(lián),但是有OID
        System.out.println(user);  
    }

Hibernate入門三

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

?

持久態(tài)對象可以自動更新數(shù)據(jù)庫

依賴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); 這句話可以省略,因?yàn)槌志脩B(tài)的對象會自動更新數(shù)據(jù)庫

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

?

Hibernate一級緩存

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

    一級緩存的特點(diǎn)

    當(dāng)應(yīng)用程序調(diào)用Session的save()、update、saveOrUpdate()的時候,Session緩存中沒有相應(yīng)的對象的時候,Hibernate會自動的從數(shù)據(jù)庫中提取對應(yīng)的數(shù)據(jù)加載到一級緩存中

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

    當(dāng)調(diào)用Session.close()的時候,session緩存會被清空。

?

測試一級緩存

觀察控制臺輸出的SQL語句

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

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

?

一級緩存內(nèi)部結(jié)構(gòu)

    Hibernate向一級緩存中存儲數(shù)據(jù)的時候,會拷貝一份數(shù)據(jù)放在Hibernate快照區(qū),當(dāng)使用事務(wù)提交之后,會根據(jù)OID比較一級緩存中的數(shù)據(jù)和快照區(qū)中的數(shù)據(jù)是否一致,如果不一致,則執(zhí)行更新操作,并且同步快照區(qū)的數(shù)據(jù),否則則不執(zhí)行任何操作。

?

Hibernate對事務(wù)的控制

?

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

?

Hibernate事務(wù)管理

?

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

      <property name="hibernate.current_session_context_class">thread</property>
        sessionFactory.getCurrentSession()
        可以不需要關(guān)閉session,線程結(jié)束之后會自動關(guān)閉
    
        thread: Session對象的生命周期與本地線程綁定
        jta:Session對象的生命周期與JTA事務(wù)綁定
        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();

            /**
             * 創(chuàng)建Query
             * 調(diào)用對象的方法
             */
            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是一個完全面對對象,可擴(kuò)展的條件查詢API,它不需要考慮數(shù)據(jù)庫底層的實(shí)現(xiàn),以及SQL語句的編寫。它是Hibernate核心查詢對象,又稱為OBC(Object By Criteria)

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

            /**
             * Criteria
             *  創(chuàng)建Criteria對象
             *  調(diào)用方法
             */
            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語句,需要我們手動封裝數(shù)據(jù)

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

            /**
             * 對象
             * 調(diào)用方法
             */
            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();
        }
    }
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI