1. 什么是緩存?
數(shù)據(jù)庫的緩存指的是應(yīng)用程序和物理數(shù)據(jù)源之間的數(shù)據(jù)。即把物理數(shù)據(jù)源的數(shù)據(jù)復(fù)制到緩存。有了緩存,可以降低應(yīng)用程序?qū)ξ锢頂?shù)據(jù)源的訪問頻率,從而提高效率。緩存的介質(zhì)一般是內(nèi)存,也可以是硬盤。
Hibernate的緩存有三種類型:一級緩存、二級緩存和查詢緩存。
2. 一級緩存
一級緩存即Session緩存,由Session自動進(jìn)行管理,不需要程序進(jìn)行干預(yù)。一級緩存根據(jù)對象的ID進(jìn)行加載和緩存。如下面的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
|
@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é)果:
1
2
3
4
5
6
7
8
9
10
11
|
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語句,并將查詢出來的對象放在一級緩存里面,第2次查詢時(shí),在一級緩存里面直接找到了這個(gè)對象,就不需要再次生成SQL語句了。
再看一個(gè)例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@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(); } |
由于一級緩存是Session級別的緩存,所以Session關(guān)閉以后,一級緩存也就不存在了,第2次查詢也要生成SQL語句:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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. 二級緩存
二級緩存即SessionFactory緩存,和一級緩存類似,也是根據(jù)對象的ID進(jìn)行加載和緩存,區(qū)別就在于一級緩存只在Session內(nèi)有效,而二級緩存在SessionFactory內(nèi)有效。在訪問某個(gè)ID的對象時(shí),先到一級緩存里面去找,如果沒有找到就到二級緩存里面去找。二級緩存包括EHCache,OSCache,SwarmCache和JBossCache等。這里以EHCache作為例子。
二級緩存需要程序進(jìn)行管理。首先,配置Maven下載相關(guān)的Jar,在pom文件里面添加:
1
2
3
4
5
6
7
8
9
10
|
<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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
< 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指明了對哪一個(gè)類進(jìn)行二級緩存。里面設(shè)置了最大緩存的對象數(shù)量,是否永久有效、最大空閑秒數(shù)、最大生存秒數(shù)、內(nèi)存滿時(shí)是否寫到硬盤,寫到硬盤的路徑等等。
修改需要緩存的類的hbm文件:
1
2
3
4
|
< class name= "com.hzhi.course.entity.Course" table= "clas" > <cache usage= "read-only" /> ...... </ class > |
usage設(shè)置了并發(fā)訪問策略,一般設(shè)置成read-only。
修改applicationContext.xml中的SessionFactory的配置,增加二級緩存的一些屬性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<!-- 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 > <!-- 二級緩存 --> < 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)行下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@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é)果:
1
2
3
4
5
6
7
8
9
10
11
|
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,但是二級緩存仍然存在,所以只生成了一次SQL語句。
下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@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é)果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
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ù)庫原理 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ù)庫原理 C語言 大學(xué)英語A Java Linux 高等數(shù)學(xué) 語文 大學(xué)物理 軟件工程 |
當(dāng)使用Query的list()方法時(shí),只生成一次SQL語句查詢出所有的對象,使用iterate()方法時(shí),會先得到所有對象的ID,然后根據(jù)每個(gè)ID生成一次SQL語句查詢。第二個(gè)Session里面使用的也是iterate()方法,首先生成一次SQL語句,得到ID,然后根據(jù)ID查找對象,由于開啟了二級緩存,在二級緩存里面找到了對象,所以就直接輸出了,并沒有再根據(jù)每個(gè)ID生成SQL語句。
不論是一級緩存還是二級緩存,都只能緩存對象,不能緩存屬性的值。下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@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é)果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
Hibernate: select course0_.NAME as col_0_0_ from clas course0_ 計(jì)算機(jī)原理 計(jì)算機(jī)網(wǎng)絡(luò) 數(shù)據(jù)庫原理 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ù)庫原理 C語言 大學(xué)英語A Java Linux 高等數(shù)學(xué) 語文 大學(xué)物理 軟件工程 ---------- |
雖然開啟了二級緩存,但是查詢的結(jié)果不是對象,是屬性,所以并沒有緩存,第2次查詢?nèi)匀簧闪瞬樵冋Z句。要解決這個(gè)問題,就需要查詢緩存。
3. 查詢緩存
在配置了二級緩存的基礎(chǔ)上,可以設(shè)置查詢緩存,在SessionFactory的設(shè)置里面加上一行:
<prop key="hibernate.cache.use_query_cache">true</prop>
即打開了查詢緩存。查詢緩存也是SessionFactory級別的緩存,在整個(gè)SessionFactory里面都是有效的。
關(guān)閉二級緩存,運(yùn)行下面的例子,在Query后面添加setCacheable(true)打開查詢緩存:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@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é)果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
Hibernate: select course0_.NAME as col_0_0_ from clas course0_ 計(jì)算機(jī)原理 計(jì)算機(jī)網(wǎng)絡(luò) 數(shù)據(jù)庫原理 C語言 大學(xué)英語A Java Linux 高等數(shù)學(xué) 語文 大學(xué)物理 軟件工程 ---------- 計(jì)算機(jī)原理 計(jì)算機(jī)網(wǎng)絡(luò) 數(shù)據(jù)庫原理 C語言 大學(xué)英語A Java Linux 高等數(shù)學(xué) 語文 大學(xué)物理 軟件工程 ---------- |
由于兩次查詢的HQL語句是一致的,所以只生成一次SQL語句。但是如果把第二次查詢改一下:
1
2
3
4
5
6
7
8
9
|
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é)果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
Hibernate: select course0_.NAME as col_0_0_ from clas course0_ 計(jì)算機(jī)原理 計(jì)算機(jī)網(wǎng)絡(luò) 數(shù)據(jù)庫原理 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語句。
查詢緩存可以緩存屬性,也可以緩存對象,但是當(dāng)緩存對象時(shí),只緩存對象的ID,不會緩存整個(gè)對象。下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@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é)果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
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ù)庫原理 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ù)庫原理 C語言 大學(xué)英語A Java Linux 高等數(shù)學(xué) 語文 大學(xué)物理 軟件工程 ---------- |
由于開了查詢緩存,沒有開二級緩存,雖然使用的是list()方法一次查詢出了所有的對象,但是查詢緩存只緩存了對象ID,沒有緩存整個(gè)對象。所以在第2個(gè)Session里面"from Course"這個(gè)HQL由于和前面的相同,并沒有生成SQL語句,但是由于沒有開二級緩存,沒有緩存整個(gè)對象,只能根據(jù)每個(gè)ID去生成一次SQL語句。雖然兩次用的都是list()方法,但是第一次是生成SQL語句去一次查詢出所有的對象,而第二次是根據(jù)查詢緩存里面的ID一個(gè)一個(gè)的生成SQL語句。
如果同時(shí)打開查詢緩存和二級緩存,第2個(gè)Session里面就不用再根據(jù)ID去生成SQL語句了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
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ù)庫原理 C語言 大學(xué)英語A Java Linux 高等數(shù)學(xué) 語文 大學(xué)物理 軟件工程 ---------- 計(jì)算機(jī)原理 計(jì)算機(jī)網(wǎng)絡(luò) 數(shù)據(jù)庫原理 C語言 大學(xué)英語A Java Linux 高等數(shù)學(xué) 語文 大學(xué)物理 軟件工程 ---------- |
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持服務(wù)器之家!
原文鏈接:http://www.cnblogs.com/mstk/p/6363351.html