ibatis结合memcache实现多tomcat共享缓存

1、下载xmemcached-1.3.8.jar

2、实现CacheController接口

MemcachedIbatisController.java

package com.xxxxxx.memcached;

import java.text.MessageFormat;
import java.util.Collections;
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.CacheKey;
import com.ibatis.sqlmap.engine.cache.CacheModel;

public class MemcachedIbatisController implements CacheController {
    private static Logger LOG = Logger.getLogger(MemcachedIbatisController.class);

    private MemcachedManager cache;
    private List<String> keyList;
    private int cacheSize;
    private boolean initExpiry = false;
    private int expiry = 0;

    public MemcachedIbatisController() {
        if (LOG.isDebugEnabled()) {
            LOG.info("Enable MemcachedIbatisController !");
        }
        this.cacheSize = 0;
        this.cache = MemcachedProxy.memcachedManager;
        this.keyList = getKeyListInstance();
    }

    public synchronized List<String> getKeyListInstance() {
        if (keyList == null) {
            keyList = Collections.synchronizedList(new LinkedList<String>());
        }
        return keyList;
    }

    public void flush(CacheModel cacheModel) {
        if (LOG.isInfoEnabled()) {
            LOG.info("Flush memcache!");
        }
        String key = null;

        try {
            if (keyList.isEmpty()) {
                cache.flushAll();
            } else
                for (int i = 0; i < keyList.size(); i++) {
                    key = keyList.get(i);
                    cache.delete(key);
                }
        } catch (Exception e) {
            LOG.error("MemcachedIbatisController method flush {}", e);
        } finally {
            if (keyList.size() > 0) {
                keyList.clear();
            }
        }
    }

    public Object getObject(CacheModel cacheModel, Object key) {
        Object result;
        String ckey = getKey(cacheModel, key);
        LOG.error(key);
        try {
            result = cache.get(ckey);
            if (cacheSize > 0) {
                keyList.remove(ckey);
                if (result != null) {
                    keyList.add(ckey);
                }
            }
        } catch (Exception e) {
            LOG.error("MemcachedIbatisController method getObject {}", e);
            return null;
        }

        if (LOG.isInfoEnabled()) {
            LOG.info(MessageFormat.format("Get the {0} from memcached, value={1}", ckey, result));
        }

        return result;
    }

    public void putObject(CacheModel cacheModel, Object key, Object object) {
        String ckey = getKey(cacheModel, key);
        keyList.add(ckey);
        try {

            if (!initExpiry) {
                expiry = new Long(cacheModel.getFlushInterval()).intValue() / 1000;
                initExpiry = true;
            }

            boolean ret = cache.set(ckey, expiry, object);
            if (LOG.isInfoEnabled()) {
                LOG.info(MessageFormat.format("Add {0} to memcached, returnt state={1}", ckey, ret));
                LOG.info("CacheSize:" + cacheSize + ", keyListSize:" + keyList.size());
            }

            if (cacheSize > 0 && keyList.size() > cacheSize) {
                String oldestKey = keyList.remove(0);
                ret = cache.delete(oldestKey);
                if (LOG.isInfoEnabled()) {
                    LOG.info(MessageFormat.format("Remove {0} to memcached, returnt state={1}", ckey, ret));
                }
            }
        } catch (Exception e) {
            LOG.error("MemcachedIbatisController method putObject {}", e);
        }

    }

    public Object removeObject(CacheModel cacheModel, Object key) {
        String ckey = getKey(cacheModel, key);
        try {
            if (keyList.contains(ckey)) {
                keyList.remove(ckey);
                if (LOG.isInfoEnabled()) {
                    LOG.info(MessageFormat.format("Remove {0} from keyList!", ckey));
                }
                boolean ret = cache.delete(ckey);
                if (LOG.isInfoEnabled()) {
                    LOG.info(MessageFormat.format("Delete {0} from memcached, returnt state={1}", ckey, ret));
                }
                return ret;
            }
        } catch (Exception e) {
            LOG.error("MemcachedIbatisController method removeObject {}", e);
        }

        return null;
    }

    public void setProperties(Properties props) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Set Properties");
        }

        String size = props.getProperty("cache-size");

        if (size != null) {
            cacheSize = Integer.parseInt(size);
        }
    }

    public int getCacheSize() {
        return cacheSize;
    }

    public void setCacheSize(int cacheSize) {
        this.cacheSize = cacheSize;
    }

    private String getKey(CacheModel cacheModel, Object cacheKey) {
        //CacheKey ck = (CacheKey)cacheKey;
        String key = cacheKey.toString();
        int keyhash = key.hashCode();
        String cacheId = cacheModel.getId();
        key = "IBATIS_CACHED" + "_" + cacheId + "_" + keyhash;
        return key;
    }

    @Override
    public void configure(Properties arg0) {
        // do what? sorry i don`t know
    }

}

3、memcache的操作类和代理

MemcachedManager.java

package com.xxxxxx.memcached;

import net.rubyeye.xmemcached.MemcachedClient;

import org.apache.log4j.Logger;

public class MemcachedManager {

    private static Logger LOG = Logger.getLogger(MemcachedManager.class);

    private static MemcachedClient memcachedClient;

    public MemcachedManager() {
        super();
    }

    public boolean set(String key, int expiry, Object o) {
        try {
            return memcachedClient.set(key, expiry, o);
        } catch (Exception e) {
            LOG.error("MemcachedManager method set {}", e);
        }
        return false;
    }

    public Object get(String key) {
        Object result = null;
        try {
            result = memcachedClient.get(key);
        } catch (Exception e) {
            LOG.error("MemcachedManager method get {}", e);
        }
        return result;
    }

    public boolean delete(String key) {
        try {
            return memcachedClient.delete(key);
        } catch (Exception e) {
            LOG.error("MemcachedManager method delete {}", e);
        }
        return false;
    }

    public void flushAll() {
        try {
            memcachedClient.flushAll();
        } catch (Exception e) {
            LOG.error("MemcachedManager method flushAll {}", e);
        }
    }

    public void setMemcachedClient(MemcachedClient memcachedClient) {
        if (null == MemcachedManager.memcachedClient)
            MemcachedManager.memcachedClient = memcachedClient;
    }

}

MemcachedProxy.java

package com.xxxxxx.memcached;

public class MemcachedProxy {

    public static MemcachedManager memcachedManager;

    public MemcachedManager getMemcachedManager() {
        return memcachedManager;
    }

    public void setMemcachedManager(MemcachedManager memcachedManager) {
        if (null == MemcachedProxy.memcachedManager)
        MemcachedProxy.memcachedManager = memcachedManager;
    }

}

4、配置spring的配置文件

该配置一定要写在ibatis配置之前,保证,先初始化(如果使用扫描器注入bean,要写在扫描器之前)

<!-- 注意:memcached 初始化要在ibatis初始化之前,否则找不到memcachedProxy对象. -->
    <!-- memcached 初始化开始 -->
    <bean id="memcachedClientBuilder" class="net.rubyeye.xmemcached.XMemcachedClientBuilder">
        <!-- XMemcachedClientBuilder have two arguments.First is server list,and
            second is weights array. -->
        <constructor-arg>
            <list>
                <bean class="java.net.InetSocketAddress">
                    <constructor-arg>
                        <value>192.168.1.80</value>
                    </constructor-arg>
                    <constructor-arg>
                        <value>11210</value>
                    </constructor-arg>
                </bean>
            </list>
        </constructor-arg>
        <property name="connectionPoolSize" value="5"></property>
        <property name="commandFactory">
            <bean class="net.rubyeye.xmemcached.command.BinaryCommandFactory"></bean>
        </property>
        <property name="sessionLocator">
            <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator"></bean>
        </property>
        <property name="transcoder">
            <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder">
                <constructor-arg>
                    <value>102400</value>
                </constructor-arg>
            </bean>
        </property>
    </bean>

    <bean id="memcachedClient" factory-bean="memcachedClientBuilder"
        factory-method="build" destroy-method="shutdown" />

    <bean id="memcachedManager" class="com.xxxxxx.memcached.MemcachedManager">
        <property name="memcachedClient">
            <ref bean="memcachedClient"/>
        </property>
    </bean>

    <bean id="memcachedProxy" class="com.xxxxxx.memcached.MemcachedProxy">
        <property name="memcachedManager">
            <ref bean="memcachedManager"/>
        </property>
    </bean>
    <!-- memcached 初始化结束 -->

5、ibatis配置文件SqlMapConfig.xml中添加对缓存的支持

<settings cacheModelsEnabled="true"
    enhancementEnabled="true"
    lazyLoadingEnabled="true"
    />

6、ibatis的sql.xml中使用CacheModel

<cacheModel id="vweb_cache" readOnly="false" serialize="true" type="com.xxxxxx.memcached.MemcachedIbatisController">
        <flushInterval hours="24" />
          <flushOnExecute statement="insertVweb" />
          <flushOnExecute statement="updateVweb" />
          <flushOnExecute statement="removeVweb" />
          <property name="cache-size" value="1000" />
    </cacheModel>
<select id="getVwebList" parameterClass="com.xxxxxx.vweb.model.Vweb" resultClass="com.xxxxxx.vweb.model.Vweb" cacheModel="vweb_cache">
        SELECT * FROM wx_vweb
            <include refid="getVwebList_body" />
            <dynamic prepend="">
                <isNotNull property="orderCol">
                    order by $orderCol$
                    <isNotNull property="ascDesc">
                        $ascDesc$
                    </isNotNull>
                </isNotNull>
            </dynamic>
            <dynamic prepend="">
                <isNotNull property="rowNumStart">
                    <isNotNull property="pageSize">
                        LIMIT #rowNumStart#,#pageSize#
                    </isNotNull>
                </isNotNull>
            </dynamic>
    </select>

7、可以启动tomcat,测试Cache是否生效(注意日志输出)

Get the IBATIS_CACHED_Vweb.vweb_cache_1438835114 from memcached, value=[[email protected]

表示缓存已经生效

8、修改ibatis源码,实现多个tomcat共享缓存

原理:memcache 为KV数据库,所以,保证同一条sql语句,同样的查询条件,在缓存时,key值一样,就实现了缓存共享

ibatis的CacheKey生成,不懂的可以百度

com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.java中最终决定CacheKey的代码

  /**
   * Add a mapped statement
   *
   * @param ms - the mapped statement to add
   */
  public void addMappedStatement(MappedStatement ms) {
    if (mappedStatements.containsKey(ms.getId())) {
      throw new SqlMapException("There is already a statement named " + ms.getId() + " in this SqlMap.");
    }
    ms.setBaseCacheKey(hashCode());
    mappedStatements.put(ms.getId(), ms);
  }
ms.setBaseCacheKey(hashCode()); 这句代码决定了basekey的生成hashCode方法的实现如下
  public int hashCode() {
    CacheKey key = new CacheKey();
    if (txManager != null) {
      key.update(txManager);
      if (txManager.getDataSource() != null) {
        key.update(txManager.getDataSource());
      }
    }
    //key.update(System.identityHashCode(this));
    key.update(DEFAULT_SYS_HASHCODE);
    return key.hashCode();
  }

注释掉的部分为原来的实现,这也就导致了不同的tomcat实例,basekey不一致

把代码进行替换,hashCode生成为固定值,保证多个tomcat中CacheKey一致

实现缓存共享

9,、替换jar包中的class文件,启动多个tomcat验证缓存的共享

时间: 2024-08-12 12:43:05

ibatis结合memcache实现多tomcat共享缓存的相关文章

windows下nginx+tomcat+memcache负载均衡tomcat集群session共享搭建

使用nginx 做负载均衡 memcached处理session共享  环境 windows 7  X64  java : jdk-7windows-x64.rar  nginx : http://nginx.org/en/download.html ,这里我们推荐下载稳定版(stable versions),本文采用nginx-1.8.0  tomcat:apache-tomcat-7.0.63 在同一台电脑上配置多个tomcat(本次采用两个tomcat来示范),修改 conf/server

SQLite剖析之异步IO模式、共享缓存模式和解锁通知

1.异步I/O模式    通常,当SQLite写一个数据库文件时,会等待,直到写操作完成,然后控制返回到调用程序.相比于CPU操作,写文件系统是非常耗时的,这是一个性能瓶颈.异步I/O后端是SQLite的一个扩展模块,允许SQLite使用一个独立的后台线程来执行所有的写请求.虽然这并不会减少整个系统的资源消耗(CPU,磁盘带宽等),但它允许SQLite在正在写数据库时立刻返回到调用者,从用户角度看,无疑提高了前端的响应速度.对异步I/O,写请求在一个独立的后台线程中被处理,这意味着启动数据库写操

SQLite学习笔记(六)&amp;&amp;共享缓存

介绍 通常情况下,sqlite中每个连接都会一个独立的pager对象,pager对象中管理了该连接的缓存信息,通过pragma cache_size指令可以设置缓存大小,默认是2000个page,每个page是1024B.这样导致了对于同一个数据文件,多个连接各自维护了自己的一份缓存,在高并发情况下,可能导致使用大量的内存.而sqlite作为一个嵌入式数据库,通常用于嵌入式设备,内存可能比较有限,为了应对这种问题,sqlite提供了一种方法,通过让多个连接公用一个pager对象,共享同一份缓存.

(转)Memcache,Redis,MongoDB(数据缓存系统)方案对比与分析

Memcache,Redis,MongoDB(数据缓存系统)方案对比与分析 数据库表数据量极大(千万条),要求让服务器更加快速地响应用户的需求. 二.解决方案: 1.通过高速服务器Cache缓存数据库数据 2.内存数据库 (这里仅从数据缓存方面考虑,当然,后期可以采用Hadoop+HBase+Hive等分布式存储分析平台) 三.主流解Cache和数据库对比: 上述技术基本上代表了当今在数据存储方面所有的实现方案,其中主要涉及到了普通关系型数据库(MySQL/PostgreSQL),NoSQL数据

阿里云服务器win2003下iis整合tomcat共享80端口

阿里云服务器win2003下iis整合tomcat共享80端口 很多机器都用tomcat跟IIS部署不同网站.最近买了阿里云的服务器.于是也想玩一下.网上百度了很多方法.但是都有缺陷说的不是很清楚.通过日志查看以及谷歌.尝试了很多方法终于配置OK.         第一.整合环境:Windows Service 2003.JDK1.60.IIS6.0 和tomcat7.0         第二.使用技术:IIS6.0和TOMCAT6.0的默认端口不用改变,使用原有的80和8081(因为本人数据库

IIS Tomcat共享80端口

为什么有这种需求, 原因是这样的, 公司有一个Java的web项目,在另一台服务器A上,最近老板一时兴起,想把他合并到这台稳定点的服务器B上,服务器B上使用IIS来寄宿asp.net 网站, 怎么办呢,硬着头皮上吧,在网上找各种解决方案: 解决方案一:isapi_redirect 这个方法按照方法试了N次就是没搞定, 解决方案二:IIS反向代理 基本逻辑就是请求来到IIS,IIS根据路由规则把请求转发给Tomcat处理,然后tomcat把响应返回给IIS, 这个方案依然只是IIS独占端口80,看

【Excle数据透视表】如何创建非共享缓存的数据透视表

一般情况下,利用同一个数据源创建多个数据表时,默认创建的是共享缓存的数据透视表.刷新一个数据透视表时会影响其他数据透视表的展示结果. 解决方案 创建非共享缓存的多个数据透视表 步骤一 单击工作表数据任意区域→插入→数据透视表→新工作表→确定→单击数据透视表→拖动字段后建立数据透视表 步骤二 按下[ALT+D+P]组合键→数据透视表→下一步→选定区域→下一步→弹窗(选择否)→现有工作表→完成

Nginx+tomcat+memcached缓存共享session

session 的序列化方案官方推荐的有 4 种: 1. java serialization 2. msm-kryo-serializer 3. msm-javolution-serializer 4. msm-xstream-serializer 这里我使用的是msm-javolution-serializer 基本架构 系统:CentOS 6.3 前端nginx代理:192.168.1.211 后端tomcat+memcached群:192.168.1.212,192.168.1.213

tomcat+redis实现session共享缓存

一:linux下redis安装 1.wget http://download.redis.io/releases/redis-3.0.6.tar.gz 2.tar xzf redis-3.0.6.tar.gz 3.rm -rf redis-3.0.6.tar.gz 4.cd redis-3.0.6 5.make 这个过程需要等一小会 6.cd src 7.   ./redis-server 注意:默认要在redis的src目录下启动 ./redis-server 以上redis安装完毕 二:to