1.简介

MyBatis 是支持普通SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC 代码和参数的手工设置以及结果集的检索。
Ehcache 是现在最流行的纯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 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。

mybatis 与 ehcache 整合[转]的更多相关文章

  1. 八 mybatis查询缓存(一级缓存,二级缓存)和ehcache整合

    1       查询缓存 1.1     什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存.

  2. Mybatis集成ehcache

    Mybatis集成ehcache 1.为什么需要缓存 拉高程序的性能 2. 什么样的数据需要缓存 很少被修改或根本不改的数据 业务场景比如:耗时较高的统计分析sql.电话账单查询sql等 3. ehc ...

  3. mybatis0210 mybatis和ehcache缓存框架整合

    .1mybatis和ehcache缓存框架整合 一般不用mybatis来管理缓存而是用其他缓存框架在管理缓存,因为其他缓存框架管理缓存会更加高效,因为别人专业做缓存的而mybatis专业做sql语句的 ...

  4. Mybatis第八篇【一级缓存、二级缓存、与ehcache整合】

    Mybatis缓存 缓存的意义 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题. myba ...

  5. mybatis二级缓存应用及与ehcache整合

    mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存. 1.开启mybatis的二级缓存 在核心配 ...

  6. MyBatis - 6.Spring整合MyBatis

    1.查看不同MyBatis版本整合Spring时使用的适配包: http://www.mybatis.org/spring/ 2.下载整合适配包 https://github.com/mybatis/ ...

  7. MyBatis笔记——EhCache二级缓存

    介绍 ehcache是一个分布式缓存框架. 我们系统为了提高系统并发,性能.一般对系统进行分布式部署(集群部署方式)  不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统开发.所以要使用分布式缓 ...

  8. Mybatis 和Spring整合之mapper代理开发

    F:\1ziliao\mybatis\代码 1.1 SqlMapConfig.xml <?xml version="1.0" encoding="UTF-8&quo ...

  9. (十四)mybatis 和 spring 整合

    目录 整合思想 整合步骤 整合之后原始 dao 开发 整合之后 Mapper 代理开发 总结 整合思想 让 spring 管理 sqlSessionFactory ,使用 单例模式 创建该对象 : 根 ...

随机推荐

  1. asp.net将数据导出到excel

    本次应用datatable导出,若用gridview(假设gridview设为了分页显示)会出现只导出当前页的情况. protected void btnPrn_Click(object sender ...

  2. 利用sfntly的sfnttool.jar提取中文字体

    雨忆博客中提到了sfntly(具体介绍可以看:https://code.google.com/p/sfntly/),利用其中sfnttool.jar就可以提取只包含指定字符的字体,如果想在页面中通过@ ...

  3. 使用Slip.js快速创建整屏滑动的手机网页

    原文  http://segmentfault.com/blog/laopopo/1190000000708417 现在滑屏网页越来越多,比如我在搜狐视频就做了好几个,举个例子,可以用手机扫描以下的二 ...

  4. 基于Jquery+Ajax+Json实现分页显示

    1.后台action产生json数据. List blackList = blackService.getBlackInfoList(mobileNum, gatewayid, startDate, ...

  5. Python 基础-python函数

    函数    1.def    2.命名    3.函数体    4.return 返回值 def get_return(): a = 1 return a 函数参数有 形参和实参    定义几个形参就 ...

  6. Day13 SQLAlchemy连表操作和堡垒机

    一.数据库操作 1.创建表.插入数据和一对多查询 #!/usr/bin/env python # -*- coding: utf-8 -*- # Author: wanghuafeng from sq ...

  7. hdu不要62

    Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来, ...

  8. xcode 工具 alcatraz---备用

    简介 Alcatraz 是一个帮你管理 Xcode 插件.模版以及颜色配置的工具.它可以直接集成到 Xcode 的图形界面中,让你感觉就像在使用 Xcode 自带的功能一样. 安装和删除 使用如下的命 ...

  9. 如何在js文件中实现获取request.getCotextPath();

    我们在jsp中可以方便的使用“request.getCotext()”来获取工程的根目录. 但是如果我们的js代码存在一个单独的js文件中,这时候再想获取根目录,我们就要自己截取了.可以采用下面的方式 ...

  10. [BZOJ 2007] [Noi2010] 海拔 【平面图最小割(对偶图最短路)】

    题目链接:BZOJ - 2007 题目分析 首先,左上角的高度是 0 ,右下角的高度是 1.那么所有点的高度一定要在 0 与 1 之间.然而选取 [0, 1] 的任何一个实数,都可以用整数 0 或 1 ...