Hibernate緩存詳解
1. 什么是緩存?
數(shù)據(jù)庫(kù)的緩存指的是應(yīng)用程序和物理數(shù)據(jù)源之間的數(shù)據(jù)。即把物理數(shù)據(jù)源的數(shù)據(jù)復(fù)制到緩存。有了緩存,可以降低應(yīng)用程序?qū)ξ锢頂?shù)據(jù)源的訪問頻率,從而提高效率。緩存的介質(zhì)一般是內(nèi)存,也可以是硬盤。
Hibernate的緩存有三種類型:一級(jí)緩存、二級(jí)緩存和查詢緩存。
2. 一級(jí)緩存
一級(jí)緩存即Session緩存,由Session自動(dòng)進(jìn)行管理,不需要程序進(jìn)行干預(yù)。一級(jí)緩存根據(jù)對(duì)象的ID進(jìn)行加載和緩存。如下面的代碼:
@Override
public void testCache() {
// TODO Auto-generated method stub
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Course c = (Course) session.get(Course.class, 1);
System.out.println("Name:" + c.getName());
c = (Course) session.get(Course.class, 1);
System.out.println("Name:" + c.getName());
tx.commit();
session.close();
}
運(yùn)行結(jié)果:
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Name:計(jì)算機(jī)原理
Name:計(jì)算機(jī)原理
第1次查詢時(shí)生成了SQL語句,并將查詢出來的對(duì)象放在一級(jí)緩存里面,第2次查詢時(shí),在一級(jí)緩存里面直接找到了這個(gè)對(duì)象,就不需要再次生成SQL語句了。
再看一個(gè)例子:
@Override
public void testCache() {
// TODO Auto-generated method stub
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Course c = (Course) session.get(Course.class, 1);
System.out.println("Name:" + c.getName());
tx.commit();
session.close();
session = sessionFactory.openSession();
tx = session.beginTransaction();
c = (Course) session.get(Course.class, 1);
System.out.println("Name:" + c.getName());
tx.commit();
session.close();
}
由于一級(jí)緩存是Session級(jí)別的緩存,所以Session關(guān)閉以后,一級(jí)緩存也就不存在了,第2次查詢也要生成SQL語句:
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Name:計(jì)算機(jī)原理
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Name:計(jì)算機(jī)原理
3. 二級(jí)緩存
二級(jí)緩存即SessionFactory緩存,和一級(jí)緩存類似,也是根據(jù)對(duì)象的ID進(jìn)行加載和緩存,區(qū)別就在于一級(jí)緩存只在Session內(nèi)有效,而二級(jí)緩存在SessionFactory內(nèi)有效。在訪問某個(gè)ID的對(duì)象時(shí),先到一級(jí)緩存里面去找,如果沒有找到就到二級(jí)緩存里面去找。二級(jí)緩存包括EHCache,OSCache,SwarmCache和JBossCache等。這里以EHCache作為例子。
二級(jí)緩存需要程序進(jìn)行管理。首先,配置Maven下載相關(guān)的Jar,在pom文件里面添加:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.1.0.Final</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.8.3</version>
</dependency>
創(chuàng)建EHCache配置文件ehcache.xml:
<ehcache>
<diskStore path="E:\Eclipse\MyWorkspace\Cache"/>
<defaultCache
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cache name="com.hzhi.course.entity.Course"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
</ehcache>
defaultCache是默認(rèn)的設(shè)置,下面一個(gè)cache指明了對(duì)哪一個(gè)類進(jìn)行二級(jí)緩存。里面設(shè)置了最大緩存的對(duì)象數(shù)量,是否永久有效、最大空閑秒數(shù)、最大生存秒數(shù)、內(nèi)存滿時(shí)是否寫到硬盤,寫到硬盤的路徑等等。
修改需要緩存的類的hbm文件:
<class name="com.hzhi.course.entity.Course" table="clas">
<cache usage="read-only"/>
......
</class>
usage設(shè)置了并發(fā)訪問策略,一般設(shè)置成read-only。
修改applicationContext.xml中的SessionFactory的配置,增加二級(jí)緩存的一些屬性:
<!-- SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" >
<ref local="dataSource"/>
</property>
<!-- 配置Hibernate的屬性 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.connection.isolation">8</prop>
<!-- 二級(jí)緩存 -->
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">WEB-INF/ehcache.xml</prop>
</props>
</property>
......
</bean>
運(yùn)行下面的例子:
@Override
public void testCache() {
// TODO Auto-generated method stub
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Course c = (Course) session.get(Course.class, 1);
System.out.println("Name:" + c.getName());
tx.commit();
session.close();
session = sessionFactory.openSession();
tx = session.beginTransaction();
c = (Course) session.get(Course.class, 1);
System.out.println("Name:" + c.getName());
tx.commit();
session.close();
}
結(jié)果:
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Name:計(jì)算機(jī)原理
Name:計(jì)算機(jī)原理
雖然關(guān)閉了Session,但是二級(jí)緩存仍然存在,所以只生成了一次SQL語句。
下面的例子:
@Override
public void testCache() {
// TODO Auto-generated method stub
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Query query = session.createQuery("from Course");
Iterator iter = query.iterate();
while(iter.hasNext()){
System.out.println(((Course)iter.next()).getName());
}
tx.commit();
session.close();
session = sessionFactory.openSession();
tx = session.beginTransaction();
query = session.createQuery("from Course");
iter = query.iterate();
while(iter.hasNext()){
System.out.println(((Course)iter.next()).getName());
}
tx.commit();
session.close();
}
結(jié)果:
Hibernate:
select
course0_.ID as col_0_0_
from
clas course0_
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
計(jì)算機(jī)原理
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
計(jì)算機(jī)網(wǎng)絡(luò)
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
數(shù)據(jù)庫(kù)原理
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
C語言
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
大學(xué)英語A
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Java
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Linux
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
高等數(shù)學(xué)
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
語文
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
大學(xué)物理
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
軟件工程
Hibernate:
select
course0_.ID as col_0_0_
from
clas course0_
計(jì)算機(jī)原理
計(jì)算機(jī)網(wǎng)絡(luò)
數(shù)據(jù)庫(kù)原理
C語言
大學(xué)英語A
Java
Linux
高等數(shù)學(xué)
語文
大學(xué)物理
軟件工程
當(dāng)使用Query的list()方法時(shí),只生成一次SQL語句查詢出所有的對(duì)象,使用iterate()方法時(shí),會(huì)先得到所有對(duì)象的ID,然后根據(jù)每個(gè)ID生成一次SQL語句查詢。第二個(gè)Session里面使用的也是iterate()方法,首先生成一次SQL語句,得到ID,然后根據(jù)ID查找對(duì)象,由于開啟了二級(jí)緩存,在二級(jí)緩存里面找到了對(duì)象,所以就直接輸出了,并沒有再根據(jù)每個(gè)ID生成SQL語句。
不論是一級(jí)緩存還是二級(jí)緩存,都只能緩存對(duì)象,不能緩存屬性的值。下面的例子:
@Override
public void testCache() {
// TODO Auto-generated method stub
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Query query = session.createQuery("select c.name from Course c");
List<String> names = query.list();
for(Iterator iter = names.iterator(); iter.hasNext();){
String name = (String) iter.next();
System.out.println(name);
}
System.out.println("----------");
query = session.createQuery("select c.name from Course c");
names = query.list();
for(Iterator iter = names.iterator(); iter.hasNext();){
String name = (String) iter.next();
System.out.println(name);
}
System.out.println("----------");
tx.commit();
session.close();
}
運(yùn)行結(jié)果:
Hibernate:
select
course0_.NAME as col_0_0_
from
clas course0_
計(jì)算機(jī)原理
計(jì)算機(jī)網(wǎng)絡(luò)
數(shù)據(jù)庫(kù)原理
C語言
大學(xué)英語A
Java
Linux
高等數(shù)學(xué)
語文
大學(xué)物理
軟件工程
----------
Hibernate:
select
course0_.NAME as col_0_0_
from
clas course0_
計(jì)算機(jī)原理
計(jì)算機(jī)網(wǎng)絡(luò)
數(shù)據(jù)庫(kù)原理
C語言
大學(xué)英語A
Java
Linux
高等數(shù)學(xué)
語文
大學(xué)物理
軟件工程
----------
雖然開啟了二級(jí)緩存,但是查詢的結(jié)果不是對(duì)象,是屬性,所以并沒有緩存,第2次查詢?nèi)匀簧闪瞬樵冋Z句。要解決這個(gè)問題,就需要查詢緩存。
3. 查詢緩存
在配置了二級(jí)緩存的基礎(chǔ)上,可以設(shè)置查詢緩存,在SessionFactory的設(shè)置里面加上一行:
<prop key="hibernate.cache.use_query_cache">true</prop>
即打開了查詢緩存。查詢緩存也是SessionFactory級(jí)別的緩存,在整個(gè)SessionFactory里面都是有效的。
關(guān)閉二級(jí)緩存,運(yùn)行下面的例子,在Query后面添加setCacheable(true)打開查詢緩存:
@Override
public void testCache() {
// TODO Auto-generated method stub
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Query query = session.createQuery("select c.name from Course c");
query.setCacheable(true);
List<String> names = query.list();
for(Iterator iter = names.iterator(); iter.hasNext();){
String name = (String) iter.next();
System.out.println(name);
}
System.out.println("----------");
query = session.createQuery("select c.name from Course c");
query.setCacheable(true);
names = query.list();
for(Iterator iter = names.iterator(); iter.hasNext();){
String name = (String) iter.next();
System.out.println(name);
}
System.out.println("----------");
tx.commit();
session.close();
}
結(jié)果:
Hibernate:
select
course0_.NAME as col_0_0_
from
clas course0_
計(jì)算機(jī)原理
計(jì)算機(jī)網(wǎng)絡(luò)
數(shù)據(jù)庫(kù)原理
C語言
大學(xué)英語A
Java
Linux
高等數(shù)學(xué)
語文
大學(xué)物理
軟件工程
----------
計(jì)算機(jī)原理
計(jì)算機(jī)網(wǎng)絡(luò)
數(shù)據(jù)庫(kù)原理
C語言
大學(xué)英語A
Java
Linux
高等數(shù)學(xué)
語文
大學(xué)物理
軟件工程
----------
由于兩次查詢的HQL語句是一致的,所以只生成一次SQL語句。但是如果把第二次查詢改一下:
System.out.println("----------");
query = session.createQuery("select c.name from Course c where c.id > 5");
query.setCacheable(true);
names = query.list();
for(Iterator iter = names.iterator(); iter.hasNext();){
String name = (String) iter.next();
System.out.println(name);
}
System.out.println("----------");
結(jié)果:
Hibernate:
select
course0_.NAME as col_0_0_
from
clas course0_
計(jì)算機(jī)原理
計(jì)算機(jī)網(wǎng)絡(luò)
數(shù)據(jù)庫(kù)原理
C語言
大學(xué)英語A
Java
Linux
高等數(shù)學(xué)
語文
大學(xué)物理
軟件工程
----------
Hibernate:
select
course0_.NAME as col_0_0_
from
clas course0_
where
course0_.ID>5
大學(xué)英語A
Java
Linux
高等數(shù)學(xué)
語文
大學(xué)物理
軟件工程
----------
由于HQL語句變了,所以第二次也生成了SQL語句。
查詢緩存可以緩存屬性,也可以緩存對(duì)象,但是當(dāng)緩存對(duì)象時(shí),只緩存對(duì)象的ID,不會(huì)緩存整個(gè)對(duì)象。下面的例子:
@Override
public void testCache() {
// TODO Auto-generated method stub
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Query query = session.createQuery("from Course");
query.setCacheable(true);
List<Course> list = query.list();
for (int i=0; i<list.size(); i++){
System.out.println(list.get(i).getName());
}
System.out.println("----------");
tx.commit();
session.close();
session = sessionFactory.openSession();
tx = session.beginTransaction();
query = session.createQuery("from Course");
query.setCacheable(true);
list = query.list();
for (int i=0; i<list.size(); i++){
System.out.println(list.get(i).getName());
}
System.out.println("----------");
tx.commit();
session.close();
}
結(jié)果:
Hibernate:
select
course0_.ID as ID0_,
course0_.NAME as NAME0_,
course0_.COMMENT as COMMENT0_
from
clas course0_
計(jì)算機(jī)原理
計(jì)算機(jī)網(wǎng)絡(luò)
數(shù)據(jù)庫(kù)原理
C語言
大學(xué)英語A
Java
Linux
高等數(shù)學(xué)
語文
大學(xué)物理
軟件工程
----------
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
計(jì)算機(jī)原理
計(jì)算機(jī)網(wǎng)絡(luò)
數(shù)據(jù)庫(kù)原理
C語言
大學(xué)英語A
Java
Linux
高等數(shù)學(xué)
語文
大學(xué)物理
軟件工程
----------
由于開了查詢緩存,沒有開二級(jí)緩存,雖然使用的是list()方法一次查詢出了所有的對(duì)象,但是查詢緩存只緩存了對(duì)象ID,沒有緩存整個(gè)對(duì)象。所以在第2個(gè)Session里面"from Course"這個(gè)HQL由于和前面的相同,并沒有生成SQL語句,但是由于沒有開二級(jí)緩存,沒有緩存整個(gè)對(duì)象,只能根據(jù)每個(gè)ID去生成一次SQL語句。雖然兩次用的都是list()方法,但是第一次是生成SQL語句去一次查詢出所有的對(duì)象,而第二次是根據(jù)查詢緩存里面的ID一個(gè)一個(gè)的生成SQL語句。
如果同時(shí)打開查詢緩存和二級(jí)緩存,第2個(gè)Session里面就不用再根據(jù)ID去生成SQL語句了:
Hibernate:
select
course0_.ID as ID0_,
course0_.NAME as NAME0_,
course0_.COMMENT as COMMENT0_
from
clas course0_
計(jì)算機(jī)原理
計(jì)算機(jī)網(wǎng)絡(luò)
數(shù)據(jù)庫(kù)原理
C語言
大學(xué)英語A
Java
Linux
高等數(shù)學(xué)
語文
大學(xué)物理
軟件工程
----------
計(jì)算機(jī)原理
計(jì)算機(jī)網(wǎng)絡(luò)
數(shù)據(jù)庫(kù)原理
C語言
大學(xué)英語A
Java
Linux
高等數(shù)學(xué)
語文
大學(xué)物理
軟件工程
----------
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!
- 詳解Java的Hibernate框架中的緩存與二級(jí)緩存
- 詳解Java的Hibernate框架中的緩存與原生SQL語句的使用
- 詳解Java的Hibernate框架中的注解與緩存
- 淺析Java的Hibernate框架中的緩存和延遲加載機(jī)制
- java模擬hibernate一級(jí)緩存示例分享
- Hibernate框架中的緩存技術(shù)詳解
- SSH框架網(wǎng)上商城項(xiàng)目第16戰(zhàn)之Hibernate二級(jí)緩存處理首頁(yè)熱門顯示
- Spring 整合 Hibernate 時(shí)啟用二級(jí)緩存實(shí)例詳解
- 詳解Hibernate緩存與性能優(yōu)化
相關(guān)文章
Java Apache Shiro安全框架快速開發(fā)詳解流程
Apache Shiro是一個(gè)強(qiáng)大且易用的Java安全框架,執(zhí)行身份驗(yàn)證、授權(quán)、密碼和會(huì)話管理。使用Shiro的易于理解的API,您可以快速、輕松地獲得任何應(yīng)用程序,從最小的移動(dòng)應(yīng)用程序到最大的網(wǎng)絡(luò)和企業(yè)應(yīng)用程序2021-10-10
Gradle修改本地倉(cāng)庫(kù)的位置方法實(shí)現(xiàn)
這篇文章主要介紹了Gradle修改本地倉(cāng)庫(kù)的位置方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
java實(shí)現(xiàn)圖片上傳至本地實(shí)例詳解
我們給大家分享了關(guān)于java實(shí)現(xiàn)圖片上傳至本地的實(shí)例以及相關(guān)代碼,有需要的朋友參考下。2018-08-08
Sentinel 整合SpringCloud的詳細(xì)教程
Spring Cloud Alibaba Sentinel 是阿里巴巴提供的,致力于提供微服務(wù)一站式解決方案,這篇文章主要介紹了Sentinel 之 整合SpringCloud的相關(guān)知識(shí),需要的朋友可以參考下2021-10-10
idea手動(dòng)執(zhí)行maven命令的三種實(shí)現(xiàn)方式
這篇文章主要介紹了idea手動(dòng)執(zhí)行maven命令的三種實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08

