博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
mybatis 与 ehcache 整合[转]
阅读量:6122 次
发布时间:2019-06-21

本文共 7914 字,大约阅读时间需要 26 分钟。

1.简介 

 是支持普通SQL 查询,存储过程和高级映射的优秀持久层框架。
MyBatis 消除了几乎所有的JDBC 代码和参数的手工设置以及结果集的检索。
 是现在最流行的纯Java开源缓存框架,配置简单、结构清晰、功能强大,最初知道它,是从Hibernate的缓存开始的。

2. 准备工作 

下载mybatis相关包与ehcache相关包
ehcache-core-2.4.4.jar
mybatis-ehcache-1.0.0.jar
slf4j-api-1.6.1.jar
slf4j-log4j12-1.6.2.jar

3. 配置步骤:

用hsqldb作为数据库,使用mybatis自定义缓存。
数据库建表语句:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
create
table
category (
    
catid
varchar
(10)
not
null
,
    
name
varchar
(80)
null
,
    
descn
varchar
(255)
null
,
    
constraint
pk_category
primary
key
(catid)
);
create
table
product (
    
productid
varchar
(10)
not
null
,
    
category
varchar
(10)
not
null
,
    
name
varchar
(80)
null
,
    
descn
varchar
(255)
null
,
    
constraint
pk_product
primary
key
(productid),
        
constraint
fk_product_1
foreign
key
(category)
        
references
category (catid)
);
create
index
productCat
on
product (category);
create
index
productName
on
product (
name
);
insert数据的语句:
1
2
3
4
INSERT
INTO
category
VALUES
(
'FISH'
,
'Fish'
,
'<image src="../images/fish_icon.gif"><font size="5" color="blue"> Fish</font>'
);
INSERT
INTO
category
VALUES
(
'DOGS'
,
'Dogs'
,
'<image src="../images/dogs_icon.gif"><font size="5" color="blue"> Dogs</font>'
);
INSERT
INTO
product
VALUES
(
'FI-SW-01'
,
'FISH'
,
'Angelfish'
,
'<image src="../images/fish1.gif">Salt Water fish from Australia'
);
INSERT
INTO
product
VALUES
(
'FI-SW-02'
,
'FISH'
,
'Tiger Shark'
,
'<image src="../images/fish4.gif">Salt Water fish from Australia'
);

4. cache配置步骤: 

(1).在classpath下配置ehcache.xml。这个是ehcache的默认配置文件。
1
2
3
4
5
6
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?> 
<
ehcache
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance" 
    
xsi:noNamespaceSchemaLocation
=
"../bin/ehcache.xsd"
    
<
defaultCache
overflowToDisk
=
"true"
eternal
=
"false"
maxElementsInMemory
=
"1"
/> 
    
<
diskStore
path
=
"D:/cache"
/> 
</
ehcache
>
(2).在需要的Mapper.xml中配置cache。
上面的配置是全局的cache,在Mapper.xml中可以根据自己的需要,对这个Mapper中进行cache的配置,可以配置某一条sql语句不进行cache。
1
2
3
4
5
6
7
8
9
10
11
12
13
<
cache
type
=
"org.mybatis.caches.ehcache.LoggingEhcache"
/> //最普通的设置,沿用全局设置
<
cache
type
=
"org.mybatis.caches.ehcache.LoggingEhcache"
>
    
<
property
name
=
"timeToIdleSeconds"
value
=
"3600"
/>
<!--1 hour-->
    
<
property
name
=
"timeToLiveSeconds"
value
=
"3600"
/>
<!--1 hour-->
    
<
property
name
=
"maxEntriesLocalHeap"
value
=
"1000"
/>
    
<
property
name
=
"maxEntriesLocalDisk"
value
=
"10000000"
/>
    
<
property
name
=
"memoryStoreEvictionPolicy"
value
=
"LRU"
/>
<
cache
>
<!--
配置这个mapper使用LRU替换策略。
(个人比较赞同这种配置,因为每个表的数据都不一样,有一些需要经常更新,有得可能某几个字段需要经常做连接,
使用一样的cache不太合适)
-->
mybatis默认是启用cache的,所以对于某一条不想被cache的sql需要把useCache="false"
1
<
select
id
=
"getCategory"
parameterType
=
"string"
resultType
=
"Category"
useCache
=
"false"
>

5. 测试:

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
private
ApplicationContext application;
private
CategoryMapper categoryMapper;
private
ProductMapper productMapper;
private
String[] categoryId = {
"FISH"
,
"DOGS"
,
"REPTILES"
,
"CATS"
,
"BIRDS"
};
@Before
public
void
initSpring() {
    
application =
new
FileSystemXmlApplicationContext(
            
"resource/applicationContext.xml"
);
    
categoryMapper = application.getBean(CategoryMapper.
class
);
    
productMapper = application.getBean(ProductMapper.
class
);
}
@Test
public
void
testSelect() {
    
// the first time
    
long
begin = System.nanoTime();
    
categoryMapper.getCategory(categoryId[
0
]);
    
long
end = System.nanoTime() - begin;
    
print(
"count :"
+ end);
    
// the second time
    
begin = System.nanoTime();
    
categoryMapper.getCategory(categoryId[
0
]);
    
end = System.nanoTime() - begin;
    
print(
"count :"
+ end);
    
// the third time
    
begin = System.nanoTime();
    
categoryMapper.getCategory(categoryId[
0
]);
    
end = System.nanoTime() - begin;
    
print(
"count :"
+ end);
    
//
}
@Test
public
void
testInsert() {
    
// the second time
    
long
begin = System.nanoTime();
    
//
    
Product p1 = productMapper.getProduct(
"FI-SW-01"
);
    
long
end = System.nanoTime() - begin;
    
print(
"count :"
+ end);
    
print(
"Category :"
+p1.getCategoryId());
    
Map<String, String> parame =
new
HashMap<String, String>();
    
parame.put(
"categoryId"
,
"DOGS"
);
    
parame.put(
"productId"
,
"FI-SW-01"
);
     
    
begin = System.nanoTime();
    
productMapper.updateProductById(parame);
    
end = System.nanoTime() - begin;
    
print(
"count :"
+end);
    
begin = System.nanoTime();
    
Product p2 = productMapper.getProduct(
"FI-SW-01"
);
    
end = System.nanoTime() - begin;
    
print(
"count :"
+end);
    
print(
"Category :"
+p2.getCategoryId());
     
}
运行的结果
log4j debug开启:
16 09:42:16,447 org.apache.ibatis.logging.slf4j.Slf4jImpl: Cache Hit Ratio [org.mybatis.jpetstore.persistence.CategoryMapper]: 0.0
DEBUG 2013-05-16 09:42:16,501 org.apache.ibatis.logging.slf4j.Slf4jImpl: ==> Executing: SELECT CATID AS categoryId, NAME, DESCN AS description FROM CATEGORY WHERE CATID = ?
DEBUG 2013-05-16 09:42:16,502 org.apache.ibatis.logging.slf4j.Slf4jImpl: ==> Parameters: FISH(String)
DEBUG 2013-05-16 09:42:16,542 org.apache.ibatis.logging.slf4j.Slf4jImpl: <== Columns: CATEGORYID, NAME, DESCRIPTION
DEBUG 2013-05-16 09:42:16,542 org.apache.ibatis.logging.slf4j.Slf4jImpl: <== Row: FISH, Fish, <image src="../images/fish_icon.gif"><font size="5" color="blue"> Fish</font>
count :204671120
Cache Hit Ratio [org.mybatis.jpetstore.persistence.CategoryMapper]: 0.5
count :3737320
Cache Hit Ratio [org.mybatis.jpetstore.persistence.CategoryMapper]: 0.6666666666666666
count :2349519
这里可以很清晰的看到,第一次取数据的时候,mybatis运行了sql语句,并且得到了返回的数据,因为是第一次,所以 Cache Hit Ratio 是0.0,当第二次的时候,因为cache已经存在查询的数据集,因此,mybatis没有发起查询,直接得到了数据。两次的时间差了100倍。
log4j INFO,关掉debug得到的查询速度快了一点
count :126226400
count :1803960
count :772080
 
inset:语句的运行。首先查一遍,让cache里面有数据,然后update里面的数据,再取出来。从所耗费的时间来看,update只是在cache进行了,只有等cache过期了,数据才会写入数据库。
count :121264080
Category :FISH
count :4028440
count :1509640
Category :DOGS

6.总结思考 

查看了一下硬盘cache的文件夹,发现mybatis对于每个Mapper都有自己独立的cache文件,查看mybatis-ehcache的实现:
private static final CacheManager CACHE_MANAGER = CacheManager.create();
每一个Mapper都对应的有自己的CacheManager。
虽然,通过log可以看到cache hit radio 但是,我需要像ehcache整合到spring那样子可以获得每个由mybatis代理运行的cache对象。查看了很久的代码,发现里面的代理对象都是私有的,并不能被用户调用,所以现在还没有找到细粒化操作mybatis cache的方法。
 
 
 
 
 
 
 
 
 
 
 
<   ehcache       
xmlns:xsi   =   "http://www.w3.org/2001/XMLSchema-instance"          xsi:noNamespaceSchemaLocation   =   "ehcache.xsd"   >        
     <   diskStore       path   =   "java.io.tmpdir"   />        
     <   defaultCache        
       maxElementsInMemory   =   "10000"        
       maxElementsOnDisk   =   "0"        
       eternal   =   "true"        
       overflowToDisk   =   "true"        
       diskPersistent   =   "false"        
       timeToIdleSeconds   =   "0"        
       timeToLiveSeconds   =   "0"        
       diskSpoolBufferSizeMB   =   "50"        
       diskExpiryThreadIntervalSeconds   =   "120"        
       memoryStoreEvictionPolicy   =   "LFU"        
       />        
     <   cache       name   =   "myCache"        
       maxElementsInMemory   =   "100"        
       maxElementsOnDisk   =   "0"        
       eternal   =   "false"        
       overflowToDisk   =   "false"        
       diskPersistent   =   "false"        
       timeToIdleSeconds   =   "120"        
       timeToLiveSeconds   =   "120"        
       diskSpoolBufferSizeMB   =   "50"        
       diskExpiryThreadIntervalSeconds   =   "120"        
       memoryStoreEvictionPolicy   =   "FIFO"        
       />        
</   ehcache   >
    
diskStore  :指定数据存储位置,可指定磁盘中的文件夹位置
defaultCache : 默认的管理策略
 
以下属性是必须的:
  1. name:  Cache的名称,必须是唯一的(ehcache会把这个cache放到HashMap里)。
  2. maxElementsInMemory:   在内存中缓存的element的最大数目。 
  3. maxElementsOnDisk:   在磁盘上缓存的element的最大数目,默认值为0,表示不限制。 
  4. eternal:   设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断。 
  5. overflowToDisk:  如果内存中数据超过内存限制,是否要缓存到磁盘上。
 
以下属性是可选的:   
  1. timeToIdleSeconds:  对象空闲时间,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问。
  2. timeToLiveSeconds:  对象存活时间,指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问。
  3. diskPersistent:  是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false。
  4. diskExpiryThreadIntervalSeconds:  对象检测线程运行时间间隔。标识对象状态的线程多长时间运行一次。
  5. diskSpoolBufferSizeMB:  DiskStore使用的磁盘大小,默认值30MB。每个cache使用各自的DiskStore。
  6. memoryStoreEvictionPolicy:  如果内存中数据超过内存限制,向磁盘缓存时的策略。默认值LRU,可选FIFO、LFU。
缓存的3 种清空策略  :
FIFO ,first in first out (先进先出).
LFU , Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。
LRU ,Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。

转载于:https://www.cnblogs.com/fx2008/p/4071092.html

你可能感兴趣的文章
HDOJ/HDU 2560 Buildings(嗯~水题)
查看>>
Maven编译时跳过Test
查看>>
Spring Boot 整合Spring Security 和Swagger2 遇到的问题小结
查看>>
[20170628]12C ORA-54032.txt
查看>>
除以2
查看>>
高可用集群原理解析
查看>>
Nginx配置URL转向tomcat
查看>>
极客Web前端开发资源大荟萃#001
查看>>
让div固定在某个位置
查看>>
Java开发环境Docker镜像
查看>>
从无到有,WebService Apache Axis2初步实践
查看>>
任务调度(一)——jdk自带的Timer
查看>>
UIKit框架(15)PCH头文件
查看>>
整理看到的好的文档
查看>>
Linux磁盘管理和文件系统管理
查看>>
Exchange2013灾难恢复演练--Exchange管理员必须掌握的技能
查看>>
本地ASP.NET开发页面使用AzureAD(AAD)验证登录
查看>>
5年了..
查看>>
使用域组策略/脚本统一配置防火墙
查看>>
我的友情链接
查看>>