文档章节

memcached整合ibatis

langke
 langke
发布于 2016/08/03 17:19
字数 1117
阅读 19
收藏 0

ibatis自带的本地缓存有FIFO,LRU等,对于分布式缓存也有osCache支持,而最常用的memcached也可以整合到ibatis里滴,这样通过map关系配置,就省了很多硬编码。
首先写个实现CacheController接口的MemcachedIbatisController类
/**
 * ibatis管理memcache 使用LRU算法
 * @author langke93
 * @date 2011-01-17
 * @usage:
 *  <cacheModel id="cache-videoinfo" type="com.woyo.upload.kernel.util.MemcachedIbatisController">
      <flushInterval seconds="3600"/>
       <flushOnExecute statement="updateVideoInfo" />
     <flushOnExecute statement="insertVideoInfo" />
     <flushOnExecute statement="deleteVideoInfo" />
      <property name="size" value="1000" />
    </cacheModel>
     @modify :
     cacheSize默认为0 ,表示由memcache管理缓存大小,推荐在集群中使用
 */
package com.woyo.upload.kernel.util;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import org.apache.log4j.Logger;
import com.ibatis.sqlmap.engine.cache.CacheController;
import com.ibatis.sqlmap.engine.cache.CacheModel;
public class MemcachedIbatisController implements CacheController {
    protected final Logger log = Logger.getLogger(this.getClass());
    private MemCachedManager cache;    
    private List<String> keyList;//keyList 管理key
    private int cacheSize;   
  
    public MemcachedIbatisController(){
        this.cacheSize = 0; //默认为0表示不限制缓存大小,不使用LRU
        this.cache = MemCachedManager.getInstance();
        this.keyList = getKeyListInstance();
        log.info("       Enable MemcachedIbatisController !");
    }   
    public synchronized List<String> getKeyListInstance(){
     if(keyList == null){
      keyList =  Collections.synchronizedList(new LinkedList<String>());
     }
     return keyList;
    }
    public void flush(CacheModel cacheModel) {
     String key = null;   
        try {
         if(keyList.isEmpty()){
          //cache.flush(); 目前清除缓存仅依赖于缓存过期,分表/条件清除缓存还需要做扩展
         }else
            for (int i=0;i<keyList.size();i++) {
             key = keyList.get(i);
          cache.delete(key);
          keyList.remove(key); 
            }
        } catch (Exception e) {   
            e.printStackTrace();   
        }
        //keyList.clear();
        log.info("       flush memcache!"); 
    }
    /**
     * 实现LRU算法
     * 把最近取过的数据放到栈顶
     */
    public Object getObject(CacheModel cacheModel, Object key) {
     Object result ;
        String ckey = getKey(cacheModel, key);
        try {
            result = cache.get(ckey);
            if(cacheSize>0){//如果缓存大小有限制,则使用LRU算法
                keyList.remove(ckey);
                if (result != null) {
                  keyList.add(ckey);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();   
            return null;   
        }
        log.info("       getObject memcache!!");
        return result ;
    }   
  
    /**
     * 如果超过缓存大小限制,移出栈底数据
     */
    public void putObject(CacheModel cacheModel, Object key, Object object) {   
        String ckey = getKey(cacheModel, key);   
        keyList.add(ckey);
        try {
         Date expiry = new Date();//过期时间
         expiry.setTime(expiry.getTime()+cacheModel.getFlushInterval());
            cache.add(ckey,object,expiry);
            log.debug("       putObject memcache!"); 
            log.info("cacheSize:"+cacheSize+",keyListSize:"+keyList.size());
            if (cacheSize>0 && keyList.size() > cacheSize) {   
                String oldestKey = keyList.remove(0);   
                cache.delete(oldestKey);   
                log.debug("       keyList.oldestKey memcache!"); 
            }   
        } catch (Exception e) {   
            e.printStackTrace();   
        }   
  
    }   
  
    public Object removeObject(CacheModel cacheModel, Object key) {
        log.info("       removeObject memcache!"); 
        String ckey = getKey(cacheModel, key);   
        try {   
            if (keyList.contains(ckey)) {
             keyList.remove(ckey);
                log.info("       removeObject memcache!"); 
                return cache.delete(ckey);   
            }   
        } catch (Exception e) {   
            e.printStackTrace();   
        }   
        return null;   
    }   
    public void setProperties(Properties props){ 
        String size = props.getProperty("size");   
        if (size == null) {
            size = props.getProperty("cache-size");   
        }   
        if (size != null) {
            cacheSize = Integer.parseInt(size);   
        }
        if(cache!=null)
         cache =  MemCachedManager.getInstance();
    }
    
    public int getCacheSize() {
        return cacheSize;
      }
      public void setCacheSize(int cacheSize) {
        this.cacheSize = cacheSize;
      }
      
    private String getKey(CacheModel cacheModel, Object cacheKey) {   
        String key = cacheKey.toString();   
        int keyhash = key.hashCode();   
        String cacheId = cacheModel.getId();
        key = Config.MEMCACHED_PRE + cacheId + "_" + keyhash; 
        return key;
    }
}
对于分布式/集群环境下,每个实例的key会不一至,也就是说A机器存入的一条SQL的KEY在B机器里算出来的KEY会不一至。原因是ibatis在key的算法里,把statement id的hash码做为key的一部分,所以需要重写CachingStatement类,修改baseCacheKey(下文高亮色的地方):
/*
 *  Copyright 2004 Clinton Begin
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.ibatis.sqlmap.engine.mapping.statement;
import com.ibatis.sqlmap.client.event.RowHandler;
import com.ibatis.sqlmap.engine.cache.CacheKey;
import com.ibatis.sqlmap.engine.cache.CacheModel;
import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
import com.ibatis.sqlmap.engine.mapping.sql.Sql;
import com.ibatis.sqlmap.engine.scope.StatementScope;
import com.ibatis.sqlmap.engine.transaction.Transaction;
import java.sql.SQLException;
import java.util.List;
/**
 * 
 * @modify langnke93
 * statement.setBaseCacheKey(0);
 * baseCacheKey使用固定值,保证每个实例的CacheKey一至
 *
 */
public class CachingStatement extends MappedStatement {
  private MappedStatement statement;
  private CacheModel cacheModel;
  public CachingStatement(MappedStatement statement, CacheModel cacheModel) {
    this.statement = statement;
    this.cacheModel = cacheModel;
  }
  public String getId() {
    return statement.getId();
  }
  public StatementType getStatementType() {
    return statement.getStatementType();
  }
  public Integer getResultSetType() {
    return statement.getResultSetType();
  }
  public Integer getFetchSize() {
    return statement.getFetchSize();
  }
  public ParameterMap getParameterMap() {
    return statement.getParameterMap();
  }
  public ResultMap getResultMap() {
    return statement.getResultMap();
  }
  public int executeUpdate(StatementScope statementScope, Transaction trans, Object parameterObject)
      throws SQLException {
    int n = statement.executeUpdate(statementScope, trans, parameterObject);
    return n;
  }
  public Object executeQueryForObject(StatementScope statementScope, Transaction trans, Object parameterObject, Object resultObject)
      throws SQLException {
    CacheKey cacheKey = getCacheKey(statementScope, parameterObject);
    cacheKey.update("executeQueryForObject");
    Object object = cacheModel.getObject(cacheKey);
    if (object == CacheModel.NULL_OBJECT){
     // This was cached, but null
     object = null;
    }else if (object == null) {
       object = statement.executeQueryForObject(statementScope, trans, parameterObject, resultObject);
       cacheModel.putObject(cacheKey, object);
    }
    return object;
  }
  public List executeQueryForList(StatementScope statementScope, Transaction trans, Object parameterObject, int skipResults, int maxResults)
      throws SQLException {
    CacheKey cacheKey = getCacheKey(statementScope, parameterObject);
    cacheKey.update("executeQueryForList");
    cacheKey.update(skipResults);
    cacheKey.update(maxResults);
    Object listAsObject = cacheModel.getObject(cacheKey);
    List list;
    if(listAsObject == CacheModel.NULL_OBJECT){
      // The cached object was null
      list = null;
    }else if (listAsObject == null) {
      list = statement.executeQueryForList(statementScope, trans, parameterObject, skipResults, maxResults);
      cacheModel.putObject(cacheKey, list);
    }else{
      list = (List) listAsObject;
    }
    return list;
  }
  public void executeQueryWithRowHandler(StatementScope statementScope, Transaction trans, Object parameterObject, RowHandler rowHandler)
      throws SQLException {
    statement.executeQueryWithRowHandler(statementScope, trans, parameterObject, rowHandler);
  }
  public CacheKey getCacheKey(StatementScope statementScope, Object parameterObject) {
  statement.setBaseCacheKey(0);// 去掉取于statement id 动态的baseCacheKey使用固定值,保证每个实例的CacheKey一至,用于集群环境
    CacheKey key = statement.getCacheKey(statementScope, parameterObject);
    if (!cacheModel.isReadOnly() && !cacheModel.isSerialize()) {
      key.update(statementScope.getSession());
    }
    return key;
  }
  public void setBaseCacheKey(int base) {
    statement.setBaseCacheKey(base);
  }
  public void addExecuteListener(ExecuteListener listener) {
    statement.addExecuteListener(listener);
  }
  public void notifyListeners() {
    statement.notifyListeners();
  }
  public void initRequest(StatementScope statementScope) {
    statement.initRequest(statementScope);
  }
  public Sql getSql() {
    return statement.getSql();
  }
  public Class getParameterClass() {
    return statement.getParameterClass();
  }
  public Integer getTimeout() {
    return statement.getTimeout();
  }
  public boolean hasMultipleResultMaps() {
    return statement.hasMultipleResultMaps();
  }
  public ResultMap[] getAdditionalResultMaps() {
    return statement.getAdditionalResultMaps();
  }
}
好了,这样就可以在map配置里引用刚才的cache实现类
 <cacheModel id="CacheVideoInfo"  readOnly="false" serialize="true" type="com.woyo.upload.kernel.util.MemcachedIbatisController">
      <flushInterval seconds="3600"/>
      <property name="size" value="1000" />
    </cacheModel>
 <statement id="updateVideoInfo" parameterClass="com.woyo.upload.kernel.entity.VideoInfo" cacheModel="CacheVideoInfo">  ....
目前清除缓存仅依赖于缓存过期,分实例/条件清除缓存还需要做扩展
 

© 著作权归作者所有

langke
粉丝 1
博文 70
码字总数 3645
作品 0
架构师
私信 提问
加载中

评论(1)

i
itxx2016
推荐国内最流行的ibatis、mybatis代码生成网站 --- fwjava.com
无需任何安装配置,直接在线生成,且十分规范好用.
现在,很多知名的互联网公司都在用它.
Spring整合Ibatis之SqlMapClientDaoSupport

Spring通过DAO模式,提供了对iBATIS的良好支持。SqlMapClient对象是iBATIS中的主要对象,我们可以通过配置让spring来管理SqlMapClient对象的创建,继而整合iBatis和Spring。 与hibernate类似...

Gillian_Male
2012/08/03
0
1
iBatis for Java 2.3.4 发布

iBatis修正了2.3.3的几个BUG后,正式版2.3.4终于出来。这个版本的改进包括: Bug [IBATIS-244] - CLONE -configured type handler not used in insert [IBATIS-512] - specifying custom bo......

oschina
2008/09/21
3K
0
iBATIS 3.0 GA (Candidate) 发布

官网上写着 GA 后面又跟着一个 Candidate ,不知何意? iBATIS 3.0 GA (Candidate) 发布了,这个版本经过了1年多,10个beta版本的测试。 iBATIS一词来源于“internet”和“abatis”的组合,是...

zhuzhangsuo
2010/04/19
2.6K
5
深入分析 iBATIS 框架之系统架构与映射原理

简介: iBATIS 通过 SQL Map 将 Java 对象映射成 SQL 语句和将结果集再转化成 Java 对象,与其他 ORM 框架相比,既解决了 Java 对象与输入参数和结果集的映射,又能够让用户方便的手写使用 ...

老盖
2010/11/11
2.2K
3
用NetBeans6.7.1开发iBATIS3程序

这真是一个艰难的探索,iBATIS也许是个不错的Framework,但是文档写的很不好,从头到尾都缺少一个完整的例子。如果习惯了微软MSDN和NetBeans.org上面的文章风格,你会觉得iBATIS的文章作者真...

长平狐
2012/08/28
145
0

没有更多内容

加载失败,请刷新页面

加载更多

【从入门到放弃-Java】并发编程-锁-synchronized

简介 上篇【从入门到放弃-Java】并发编程-线程安全中,我们了解到,可以通过加锁机制来保护共享对象,来实现线程安全。 synchronized是java提供的一种内置的锁机制。通过synchronized关键字同...

阿里云云栖社区
32分钟前
1
0
数据可视化分析除了需要编码的Python,还有更简单的方式吗?

大数据、数据分析的兴起和火爆,也带动了数据可视化的广泛应用。说起数据分析和可视化的关系,就好比你为一堆散乱的拼图写了一份说明,告诉他这个数据是什么样子,代表什么。可以说,数据可视...

NBI大数据可视化
47分钟前
0
0
远程桌面中文版使用时的问题原因及解决办法

  微软现在更新了远程桌面服务的中文补丁,但是即便是中文的,在使用的过程中还是会出现很多问题, 下面几个问题出现的原因和解决办法,请大家知晓。   1 找不到指定的远程计算机。确认输...

takethelas
56分钟前
0
0
PostgreSQL在启动时如何分配共享缓存

相信很多人知道 shared_buffers 这个参数,它设置共享缓存的大小,本篇简单讲一下它是怎样分配的。 1、参数设置(src/backend/utils/misc/guc.c) /* * We sometimes multiply the numbe...

有理想的猪
今天
4
0
jsonFormat注解导致时间后台和页面差8小时

阿里云提醒fastjson < 1.2.51 远程代码执行漏洞。 jar包升级1.1.40升级到1.2.58后前台和后台拿到的时间数据差8小时。 解决方法,在实体注解上添加内容 @JsonFormat(pattern = "yyyy-MM-dd HH...

S三少S
今天
49
2

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部