Hibernate緩衝以及哪些操作會向緩衝中讀取和存放資料

來源:互聯網
上載者:User
Hibernate緩衝以及哪些操作會向緩衝中讀取和存放資料 Hibernate緩衝

Hibernate有兩級緩衝,分別是一級緩衝和二級緩衝。一級緩衝也叫Session級緩衝,預設情況下就可以用,無需配置。一級緩衝生命週期由Session對象決定,Session對象關閉,一級緩衝也就消失。二級緩衝也叫SessionFactory級緩衝,需要配置後才能使用。二級緩衝的生命週期比一級緩衝的生命週期長,由SessionFactory對象決定,SessionFactory對象關閉,二級緩衝也就消失。 哪些操作會向緩衝中讀取和存放資料。

測試之前先說一下Hibernate訪問資料庫,Hibernate對傳統的JDBC進行了封裝,一般我們訪問資料庫無非就是增、刪、改、查這四個操作,而這四個操作均通過各自的SQL陳述式完成,所以Hibernate對資料庫進行這四個操作時也離開不了SQL語句,如果我們配置Hibernate時配置了show_sql這個屬性的話,一旦Hibernate對資料庫進行了增、刪、改、查操作的話,控制台就會將執行的SQL語句列印出來,這也就是下面我們為什麼能將控制台有沒有列印SQL語句作為Hibernate有沒有訪問資料庫的原因。下面開始測試:

測試環境:
系統:Windows 10
JDK:1.8.102
Hibernate:5.2.10
軟體:MyEclipse 2016

我們先看查詢,查詢我們常見的有get()、load()以及HQL中的Query對象的list()方法(後面為方便,我們稱為query.list())和uniqueResult()方法(後面為方便,我們稱為query.uniqueResult())這些方法。

先上結果:
get()、load()均會向緩衝中存放以及讀取資料,而query.list()和query.uniqueResult()會向緩衝存放資料但不會從緩衝中讀取資料

get()方法:

測試之前先說一下get()方法是怎麼尋找資料的,它會先到一級緩衝中去找,沒有的話,它會到二級緩衝中繼續找,二級緩衝中還沒有的話,就會立馬產生相應的查詢SQL,並把這個SQL發送到資料庫,到資料庫中去找編號為7499的員工,如果資料庫中也沒找到的話,就會返回null。如果資料庫中有的話就會返回查詢結果,在它返回查詢結果的同時,它還會把查到的結果放進緩衝中(一二級緩衝都會放)。

測試get()方法代碼:

    // get()會向緩衝中存放和讀取資料測試    public static void testGetCache(Session session){        try {            Employee emp6=session.get(Employee.class, 7499);            System.out.println(emp6);            Employee emp7=session.get(Employee.class, 7499);            System.out.println(emp7);        } catch (Exception e) {            e.printStackTrace();        }finally{            session.close();        }    }

運行結果:

Hibernate:     select        employee0_.empno as empno1_0_0_,        employee0_.ename as ename2_0_0_,        employee0_.job as job3_0_0_,        employee0_.sal as sal4_0_0_,        employee0_.deptno as deptno5_0_0_,        employee0_.hiredate as hiredate6_0_0_,        employee0_.comm as comm7_0_0_,        employee0_.mgr as mgr8_0_0_     from        SCOTT.Emp employee0_     where        employee0_.empno=?員工姓名:ALLEN  員工編號7499員工姓名:ALLEN  員工編號7499

代碼中我們查詢編號7499的員工查了2次,但運行結果中只列印了第一次查詢的SQL語句,說明第一次是到資料庫中查的,第二次沒有去資料庫中查,但第二次卻依然查到了編號7499的員工,原因是因為Hibernate的緩衝機制,第一次找到編號為7499的員工到後就會把7499的員工資訊放進緩衝中,當我們第二次再次尋找的7499的員工資訊時,由於在緩衝中已經找到了,所以就直接返回結果,就不會到資料庫中去查了,因此控制台並沒有列印第二次的SQL語句。也就是說第二次查詢是從緩衝中查(讀取)出來的。所以結果很明顯:get()會向緩衝中存放以及讀取資料。
get()測試結果:get()會向緩衝中存放以及讀取資料

load()方法:

load()和get()尋找資料的方式差不多,但又有點區別。load()也是先到一級緩衝中去找,沒找到的話繼續到二級緩衝中找,二級緩衝中還沒找到的話,它會返回一個查詢結果的代理對象,當後面我們用到查詢結果時,這個時候它才會產生相應的SQL語句,並把SQL發送到資料庫,到資料庫中去找,你後面如果沒用到查詢結果的話它不會產生查詢的SQL,不會到資料庫中去找。換句話說,就是你什麼時候用到查詢結果,他就什麼時候去資料庫中找,如果在資料庫中沒找到的話,就會報錯,會報org.hibernate.ObjectNotFoundException的異常,導致程式中斷。如果資料庫中有的話就會返回查詢結果,在它返回查詢結果的同時,它還會把查到的結果放進緩衝中(一二級緩衝都會放)

測試load()方法代碼:

    // load()會向緩衝中存放和讀取資料測試    public static void testLoadCache(Session session){        try {          Employee emp6=session.get(Employee.class, 7369);          System.out.println(emp6);          Employee emp7=session.get(Employee.class, 7369);          System.out.println(emp7);        } catch (Exception e) {            e.printStackTrace();        }finally{            session.close();        }    }

運行結果:

Hibernate:     select        employee0_.empno as empno1_0_0_,        employee0_.ename as ename2_0_0_,        employee0_.job as job3_0_0_,        employee0_.sal as sal4_0_0_,        employee0_.deptno as deptno5_0_0_,        employee0_.hiredate as hiredate6_0_0_,        employee0_.comm as comm7_0_0_,        employee0_.mgr as mgr8_0_0_     from        SCOTT.Emp employee0_     where        employee0_.empno=?員工姓名:SMITH  員工編號7369員工姓名:SMITH  員工編號7369

代碼中我們同樣查詢編號7369的員工查了2次,但運行結果中只列印了第一次查詢的SQL語句,說明第一次是到資料庫中查的,第二次沒有去資料庫中查,但第二次卻依然查到了編號7369的員工,原因也是因為Hibernate的緩衝機制,第一次找到編號為7369的員工後就會把7369的員工資訊放進了緩衝,第二次尋找的7369的員工資訊是從緩衝中查(讀取)出來的。所以load()也會向緩衝中存放以及讀取資料。
load()方法測試結果:load()會向緩衝中存放以及讀取資料

query.list()方法

測試query.list()方法代碼:

    // 測試query.list()會向緩衝中存放資料但不會從緩衝的讀取資料    public static void testQueryListCache(Session session) {        try {            String hql="from Employee";            Query query=session.createQuery(hql);            List<Employee> list=query.list();            for (int i=0;i<2;i++) {                System.out.println("員工編號:"+list.get(i).getEmpNo()+"   員工姓名:"+list.get(i).getEmpName());            }            System.out.println("------------------------------------------");            Employee emp=(Employee)session.get(Employee.class, 7654);            System.out.println("員工編號:"+emp.getEmpNo()+"   員工姓名:"+emp.getEmpName());            System.out.println("------------------------------------------");            String hql2="from Employee";            Query query2=session.createQuery(hql2);            List<Employee> list2=query2.list();            for (int i=0;i<2;i++) {                System.out.println("員工編號:"+list2.get(i).getEmpNo()+"   員工姓名:"+list2.get(i).getEmpName());            }        } catch (Exception e) {            e.printStackTrace();        }finally{            session.close();        }    }

運行結果:

Hibernate:     select        employee0_.empno as empno1_0_,        employee0_.ename as ename2_0_,        employee0_.job as job3_0_,        employee0_.sal as sal4_0_,        employee0_.deptno as deptno5_0_,        employee0_.hiredate as hiredate6_0_,        employee0_.comm as comm7_0_,        employee0_.mgr as mgr8_0_     from        SCOTT.Emp employee0_員工編號:20   員工姓名:empSu2員工編號:19   員工姓名:empSave2------------------------------------------員工編號:7654   員工姓名:MARTIN------------------------------------------Hibernate:     select        employee0_.empno as empno1_0_,        employee0_.ename as ename2_0_,        employee0_.job as job3_0_,        employee0_.sal as sal4_0_,        employee0_.deptno as deptno5_0_,        employee0_.hiredate as hiredate6_0_,        employee0_.comm as comm7_0_,        employee0_.mgr as mgr8_0_     from        SCOTT.Emp employee0_員工編號:20   員工姓名:empSu2員工編號:19   員工姓名:empSave2

測試代碼中我們用query.list()方法去查詢所有員工的編號和姓名查了兩次(為了方便看結果,迴圈列印員工的編號和姓名時只迴圈了2次),分別在第一條虛線前和第二條虛線後。兩條虛線之間我們用get()的方式尋找了其中一名員工,看兩條虛線間有沒有列印get()查詢員工的SQL語句來驗證第一次query.list()查詢後,有沒有向緩衝中存放資料。

運行結果可以看出,控制台將這兩次query.list()查詢所有員工的SQL語句都列印了出來,說明兩次query.list()查詢都是到資料庫中尋找的。兩次query.list()查詢之間我們用get()去查詢了編號為7654的員工,運行結果顯示我們查到了該員工的資訊,但控制台卻沒有列印查詢該員工資訊的SQL語句,說明get()沒有到資料庫中去查,get()查到的編號為7654的員工資訊不是從資料庫中查到的,由於get()尋找資料的順序是先從緩衝中找再到資料庫中找,但我們用get()卻查到了編號為7654的員工,說明get()查到的資料是從緩衝中查到(讀取到)的,觀察整段測試代碼,get()查詢之前我們只進行了query.list()查詢操作,所以很明顯緩衝中的資訊是query.list()查到結果後放進去的,這就說明了query.list()會向緩衝中存放資料,此時緩衝中已經有了所有員工資訊,但get()後面的query.list()查詢操作在緩衝中已經有要尋找的資訊時依舊是到資料庫中查的,所以會發現query.list()並不會從緩衝中尋找(讀取)資料。綜上:測試query.list()會向緩衝中存放資料但不會從緩衝的讀取資料
query.list()測試結果:query.list()會向緩衝中存放資料但不會從緩衝的讀取資料

query.uniqueResult()方法:

測試query.uniqueResult()代碼:

    //測試query.uniqueResult()會向緩衝中存放資料但不會從緩衝的讀取資料    public static void testQueryUniqueResultCache(Session session) {        try {            String hql="from Employee where empNo=7876";            Query query=session.createQuery(hql);            Employee emp=(Employee)query.uniqueResult();            System.out.println("員工編號:"+emp.getEmpNo()+"   員工姓名:"+emp.getEmpName());            System.out.println("-------------------------------------------------");            //通過get()來測試query.list()有沒有向緩衝中存放資料            Employee emp3=(Employee)session.get(Employee.class, 7876);            System.out.println("員工編號:"+emp3.getEmpNo()+"   員工姓名:"+emp3.getEmpName());            System.out.println("-------------------------------------------------");            String hql2="from Employee where empNo=7876";            Query query2=session.createQuery(hql2);            Employee emp2=(Employee)query.uniqueResult();            System.out.println("員工編號:"+emp2.getEmpNo()+"   員工姓名:"+emp2.getEmpName());        } catch (Exception e) {            e.printStackTrace();        }finally{            session.close();        }    }

運行結果:

Hibernate:     select        employee0_.empno as empno1_0_,        employee0_.ename as ename2_0_,        employee0_.job as job3_0_,        employee0_.sal as sal4_0_,        employee0_.deptno as deptno5_0_,        employee0_.hiredate as hiredate6_0_,        employee0_.comm as comm7_0_,        employee0_.mgr as mgr8_0_     from        SCOTT.Emp employee0_     where        employee0_.empno=7876員工編號:7876   員工姓名:ADAMS-------------------------------------------------員工編號:7876   員工姓名:ADAMS-------------------------------------------------Hibernate:     select        employee0_.empno as empno1_0_,        employee0_.ename as ename2_0_,        employee0_.job as job3_0_,        employee0_.sal as sal4_0_,        employee0_.deptno as deptno5_0_,        employee0_.hiredate as hiredate6_0_,        employee0_.comm as comm7_0_,        employee0_.mgr as mgr8_0_     from        SCOTT.Emp employee0_     where        employee0_.empno=7876員工編號:7876   員工姓名:ADAMS

與上面的測試query.list()類似,我們用query.uniqueResult()查編號為7876的員工查了兩次,分別是在第一條虛線前和 第二條虛線後。兩條虛線中間我們用get()再次尋找編號7876的員工,看兩條虛線之間有沒有列印get()查詢的SQL語句來判斷query.uniqueResult()有沒有向緩衝中放入資料。

結果顯示兩條虛線之外均有列印查詢的SQL,說明兩次query.uniqueResult()查詢都是到資料庫中去查的,從運行結果來看,兩條虛線之間並沒有列印SQL語句,說明我們用get()尋找員工7876時並沒有到資料庫中去查,但是依然查到了員工資訊,根據get()尋找資料的順序結合此時get()並沒有到資料庫中去查,可以知道,get()查到員工資訊是從緩衝中查(讀取)到的,依舊是觀察整段測試代碼,get()查詢員工前面除了query.uniqueResult()查詢操作外並沒有進行其它任何操作,所以,很顯然,緩衝中的員工資訊是前面query.uniqueResult()查到結果後放進去的。到這就說明了query.uniqueResult()會向緩衝中存放資料。
再來,結合get()後面的query.uniqueResult()查詢操作,在緩衝中已經有要尋找的員工時,卻還是到資料庫中去尋找。所以得出結論:query.uniqueResult()不會從緩衝的讀取資料。
綜合就是:query.uniqueResult()會向緩衝中存放資料但不會從緩衝的讀取資料

測試結果:query.uniqueResult()會向緩衝中存放資料但不會從緩衝的讀取資料

說完了查詢,我們說添加,添加我們常見的有save()和saveOrUpdate()
先上結果:
save()和saveOrUpdate()進行添加時,均會向緩衝中存放資料。

save()方法:

測試save()方法代碼

    //測試save()會向緩衝中存放資料    public static void testSaveCache(Session session) {        try {            Transaction tr=session.beginTransaction();            Employee emp1=new Employee();            emp1.setEmpName("empSave2");            session.save(emp1);            System.out.println("添加的對象的主鍵為:"+emp1.getEmpNo());            Employee emp2=(Employee)session.get(Employee.class,emp1.getEmpNo());            System.out.println("員工姓名:"+emp2.getEmpName());            tr.commit();//只有當這句代碼執行時,才會向資料庫發送sql        } catch (Exception e) {            e.printStackTrace();        }finally{            session.close();        }    }

運行結果:

Hibernate:     select        hibernate_sequence.nextval     from        dual添加的對象的主鍵為:19員工姓名:empSave2Hibernate:     insert     into        SCOTT.Emp        (ename, job, sal, deptno, hiredate, comm, mgr, empno)     values        (?, ?, ?, ?, ?, ?, ?, ?)

從代碼可以看出,我們在tr.commit();這句代碼之前我們又用get()查詢了當前添加的對象,此時tr.commit();還沒有執行,也就是事務還沒提交,所以對象這個時候還沒存進資料庫,按理說我們應該查不到記錄。

但從運行結果中可以看出,我們查到了資料,而且,控制台沒有列印相關的查詢SQL,說明我們用get()尋找的員工資訊不是從資料庫中找的,結合get()尋找資料是先從緩衝再到資料庫中找的順序,所以我們能得出,查到的資料是從緩衝中查到的,而在我們get()查詢之前除了save()操作並沒有其它操作,因此,緩衝中的資料是save()放的,也就是說在我們調用save()添加時它會把添加的資訊放進緩衝裡。
save()測試結果:save()會向緩衝中存放資料

saveOrUpdate()方法:

測試saveOrUpdate()方法代碼

    //測試saveOrUpdate()進行添加時會向緩衝中存放資料    public static void testSaveOrUpdateCache(Session session) {        try {            Transaction tx=session.beginTransaction();            Employee emp3=new Employee();            emp3.setEmpName("empSu2");            session.saveOrUpdate(emp3);            System.out.println("添加的對象的主鍵為:"+emp3.getEmpNo());            Employee emp4=(Employee)session.get(Employee.class,emp3.getEmpNo());            System.out.println("員工姓名:"+emp4.getEmpName());            tx.commit();//只有當這句代碼執行時,才會向資料庫發送sql        } catch (Exception e) {            e.printStackTrace();        }finally{            session.close();        }    }

運行結果:

Hibernate:     select        hibernate_sequence.nextval     from        dual添加的對象的主鍵為:20員工姓名:empSu2Hibernate:     insert     into        SCOTT.Emp        (ename, job, sal, deptno, hiredate, comm, mgr, empno)     values        (?, ?, ?, ?, ?, ?, ?, ?)

和測試save()一樣,我們在tx.commit();這句代碼之前我們又用get()查詢了當前添加的對象,此時tr.commit();還沒有執行,也就是事務還沒提交,所以對象還沒存進資料庫,按理說我們應該查不到記錄。

運行結果也和上面save()的一樣,控制台並沒有列印相關的查詢SQL說明,說明我們用get()尋找的員工資訊不是從資料庫中找的,結合get()尋找資料是先從緩衝再到資料庫中找的順序,所以我們能得出,查到的資料是從緩衝中查到的,而在我們get()查詢之前除了saveOrUpdate()操作並沒有其它操作,因此,緩衝中的資訊是saveOrUpdate()操作放進去的,所以,saveOrUpdate()也會向緩衝中存放資料。
saveOrUpdate()測試結果:saveOrUpdate()會向緩衝中存放資料

以上均為個人理解,如有錯誤,歡迎指正

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.