Hibernate一級緩存
緩存就是你去小賣鋪買東西,不用再去生產車間里買東西,當小賣鋪倒閉了,也就是session緩存生命周期結束。hibernate一級緩存的聲明周期很短,和session的生命周期一致,hibernate的一級緩存也叫做session級緩存,或叫事務級緩存。下面來看session控制的一級緩存。
### 同一session中使用兩次load()進行查詢。
代碼入下所示,我們在同一個session中兩次調用load()。
~~~
/**
* 在同一個session中發出兩次load查詢
*/
public voidtestCache1() {
Sessionsession = null;
try {
//使用load查詢兩遍.
session= HibernateUtils.getSession();
session.beginTransaction();
Studentstudent =(Student)session.load(Student.class, 1);
System.out.println("student.name=" + student.getName());
//不會發出查詢語句,load使用緩存,在同一個session中.
student =(Student)session.load(Student.class, 1);
System.out.println("student.name=" + student.getName());
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
兩次都采用load()進行加載并打印出學生的名字。發出的sql語句如下所示。對于loadlazy加載,只有在使用load加載上來的類,才真正的去數據庫查詢。控制臺打印的sql代碼如下所示。

從顯示結果中我們可以看出,在第一次真正使用load的時候,發出sql語句。Hibernate會把查詢上來真實的對象放到session的map中。當第二次load再次使用的時候,不會再發送sql語句,而是直接從session的緩存中取出。
### 同一session中使用兩次get()進行查詢。
源代碼也就是把上述load換成get。
Get和load的區別,get不支持延遲加載而load支持延遲加載,但當我們在同一次訪問中訪問兩次get方法時,可以看到當加載get方法的時候控制臺立刻打印sql,同時放到了緩存中。當我們第一次調用get方法的時候,同樣和load方法一樣,沒有再次去數據庫中查詢,而是直接從緩存中取出來顯示。打印結果如下圖所示。

### 在同一session中發出兩次iterate查詢,查詢實體對象。
代碼如下所示。
~~~
/**
* 在同一個session中發出兩次iterate查詢,查詢實體對象
* 發出兩次迭代查詢.查詢實體對象.
*/
public void testCache3() {
Sessionsession = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
Iteratoriter = session.createQuery("from Student s where s.id<5").iterate();
while(iter.hasNext()) {
Studentstudent = (Student)iter.next();
System.out.println(student.getName());
}
System.out.println("--------------------------------------");
//它會發出查詢id的語句,但不會發出根據id查詢學生的語句,因為iterate使用緩存
iter= session.createQuery("from Student s where s.id<5").iterate();
while(iter.hasNext()) {
Studentstudent = (Student)iter.next();
System.out.println(student.getName());
}
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
運行結果如下所示。

第一次調用迭代器的查詢時,首先發出查詢id的語句,并根據id查詢學生。當第二次調用時,只會發出查詢id的語句,不會再根據id來查詢對應的學生對象。這說明iterate(迭代器)是支持緩存的。
### 在同一session中發出兩次iterate查詢,查詢實體對象。
代碼如下所示。
~~~
Session session = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
Iteratoriter = session.createQuery("select s.name from Student s wheres.id<5").iterate();
while(iter.hasNext()) {
Stringname = (String)iter.next();
System.out.println(name);
}
System.out.println("--------------------------------------");
//iterate查詢普通屬性,一級緩存不會緩存,所以發出查詢語句
//一級緩存是緩存實體對象的
iter= session.createQuery("select s.name from Student s wheres.id<5").iterate();
while(iter.hasNext()) {
Stringname = (String)iter.next();
System.out.println(name);
}
session.getTransaction().commit();
~~~
顯示結果如下所示。

根據顯示結果可知,迭代器查詢普通屬性,一級緩存不會存儲,所以當第二次查詢的時候仍然發出查詢語句。這說明iterate一級緩存緩存的是實體對象,對于普通屬性不會緩存。
在兩個session中發出load查詢。
代碼如下所示。
~~~
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Studentstudent = (Student)session.load(Student.class, 1);
System.out.println("student.name=" +student.getName());
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Studentstudent = (Student)session.load(Student.class, 1);
//會發出查詢語句,session間不能共享一級緩存數據
//因為他會伴隨著session的消亡而消亡
System.out.println("student.name=" +student.getName());
session.getTransaction().commit();
~~~
顯示結果如下所示。

從上圖可以看出,會發出兩次sql,這也說明了session之間不能共享一級緩存數據,因為緩存會本隨著自己的那個session的消亡而消亡。
### 在一個session中先調用save(),再調用get或load查詢剛剛save的數據。
代碼如下所示。
~~~
/**
* 在同一個session中先調用save,再調用load查詢剛剛save的數據
*/
public voidtestCache6() {
Sessionsession = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
Studentstudent = new Student();
student.setName("張三");
Serializableid = session.save(student);
student= (Student)session.load(Student.class,id);
//不會發出查詢語句,因為save支持緩存
System.out.println("student.name=" +student.getName());
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
顯示結果如下所示。

從圖中可以看出,只發送一次插入語句,當我們再次查詢的時候,沒有去數據庫進行查詢,這說明當使用session.save()時,已經放入緩存中。再進行查詢時會從緩存中取出。
### 大批量數據的添加。
代碼如下所示。
~~~
public voidtestCache7() {
Sessionsession = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
for (int i=0;i<100; i++) {
Studentstudent = newStudent();
student.setName("張三" +i);
session.save(student);
//每20條更新一次
if (i %20 == 0) {
session.flush();
//清除緩存的內容
session.clear();
}
}
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
打印sql如下圖所示。

從圖中可知,打印了100條inset語句,在一個session中緩存100條數據很大,我們可以設置每20條清空緩存。
### Hibernate一級緩存總結
從上可知,load、get、iterate查詢實體對象時,支持一級緩存,但查詢普通屬性時不支持一級緩存,當我們大批量數據插入或更新時,由于緩存中數據量太大,我們可以設置緩存中的條數,使用session.clear()來清除緩存。
- 前言
- Struts旅程(一)Struts簡介和原理
- struts旅程(二)Struts登錄示例
- Struts旅程(三)Struts表單處理器ActionForm(靜態動態)
- Struts旅程(四)MVC向struts MVC框架演變過程
- Struts旅程(五)struts控制器DispatchAction
- Struts旅程(六)Struts頁面轉發控制ActionForward和ActionMapping
- Hibernate旅程(一)Hibernate架構概述
- Hibernate旅程(二)Hibernate實例
- Hibernate旅程(三)Hibernate持久化對象的三個狀態
- Hibernate旅程(四)Hibernate對數據庫刪除、查找、更新操作
- Hibernate旅程(五)Hibernate映射--基本類映射和對象關系映射
- Hibernate旅程(六)Hibernate映射--繼承映射
- Hibernate旅程(七)Hibernate緩存機制--一級緩存
- Hibernate旅程(八)Hibernate緩存機制--二級緩存
- Hibernate旅程(九)Hibernate緩存機制--查詢緩存
- Spring旅程(一)為什么使用Spring
- Spring旅程(二)非Spring向Spring過渡-- Spring IOC容器的使用
- Spring旅程(三) AOP--Spring AOP容器基礎
- Spring旅程(四) AOP--Spring AOP實例
- SSH旅程(五)Spring運用到Hibernate中
- SSH旅程(六)Spring和struts結合(方案一)