IBatis框架的一些问题的扩展(二)

            项目中由于Ibatis自身的缓存的鸡肋性(Ibatis自身的缓存是查询字符串和相应的结果的缓存,效率非常有效并且很容易占用内存,采用大量的缓存时,Ibatis严重的影响效率),进行相应的扩展的采用OSCache进行对象缓存。

 iBatis整理——EhCache支持扩展

项目完结,整理一些技术方面的相关收获。 
已经记不得EhCacheController这个实现类最早来自于那里了,总之稍加修改后非常有效果,大家就这么用了,感谢最初开源的那位兄弟。这里,主要是做个记录,为以后类似扩展(譬如Memcached)做个准备。 

iBatis提供CacheController接口,用于实现第三方缓存架构的扩展。 
这里以iBatis 2.3.0,EhCache 1.2.3版本为基础,构建iBatis+EhCache实现。 

EhCacheController类: 

Java代码     收藏代码
  1. package com.ibatis.sqlmap.engine.cache.ehcache;  
  2.   
  3. import java.net.URL;  
  4. import java.util.Properties;  
  5.   
  6. import net.sf.ehcache.Cache;  
  7. import net.sf.ehcache.CacheManager;  
  8. import net.sf.ehcache.Element;  
  9.   
  10. import com.ibatis.sqlmap.engine.cache.CacheController;  
  11. import com.ibatis.sqlmap.engine.cache.CacheModel;  
  12.   
  13. /** 
  14.  * EhCache Implementation of the 
  15.  * {@link com.ibatis.sqlmap.engine.cache.CacheController} interface to be able 
  16.  * to use EhCache as a cache implementation in iBatis. You can configure your 
  17.  * cache model as follows, by example, in your sqlMapping files: 
  18.  *  
  19.  * <pre> 
  20.  * <code> 
  21.  * <cacheModel id="myCache" readOnly="true" serialize="false" 
  22.  *  type="com.ibatis.sqlmap.engine.cache.EhCacheController" >  
  23.  *  <property name="configLocation" 
  24.  *      value="/path-to-ehcache.xml"/>  
  25.  * </cacheModel> </code> 
  26.  * </pre> 
  27.  *  
  28.  * Alternatively, you can use a type alias in your type attribute and defining 
  29.  * the class with a <code><typeAlias></code> declaration: 
  30.  *  
  31.  * <pre> 
  32.  * <code> 
  33.  * <sqlMapConfig> 
  34.  *  <typeAlias alias="EHCACHE"  
  35.  *      type="com.ibatis.sqlmap.engine.cache.ehcache.EhCacheController" /> 
  36.  * </sqlMapConfig> 
  37.  * </code> 
  38.  * </pre> 
  39.  *  
  40.  */  
  41. public class EhCacheController implements CacheController {  
  42.   
  43.     /** 
  44.      * The EhCache CacheManager. 
  45.      */  
  46.     private CacheManager cacheManager;  
  47.   
  48.     public static final String CONFIG_LOCATION = "configLocation";  
  49.   
  50.     /** 
  51.      * Default Configure Location 
  52.      */  
  53.     public static final String DEFAULT_CONFIG_LOCATION = "/ehcache.xml";  
  54.   
  55.     /** 
  56.      * Flush a cache model. 
  57.      *  
  58.      * @param cacheModel 
  59.      *            - the model to flush. 
  60.      */  
  61.     public void flush(CacheModel cacheModel) {  
  62.         getCache(cacheModel).removeAll();  
  63.     }  
  64.   
  65.     /** 
  66.      * Get an object from a cache model. 
  67.      *  
  68.      * @param cacheModel 
  69.      *            - the model. 
  70.      * @param key 
  71.      *            - the key to the object. 
  72.      * @return the object if in the cache, or null(?). 
  73.      */  
  74.     public Object getObject(CacheModel cacheModel, Object key) {  
  75.         Object result = null;  
  76.         Element element = getCache(cacheModel).get(key);  
  77.         if (element != null) {  
  78.             result = element.getObjectValue();  
  79.         }  
  80.         return result;  
  81.   
  82.     }  
  83.   
  84.     /** 
  85.      * Put an object into a cache model. 
  86.      *  
  87.      * @param cacheModel 
  88.      *            - the model to add the object to. 
  89.      * @param key 
  90.      *            - the key to the object. 
  91.      * @param object 
  92.      *            - the object to add. 
  93.      */  
  94.     public void putObject(CacheModel cacheModel, Object key, Object object) {  
  95.         getCache(cacheModel).put(new Element(key, object));  
  96.     }  
  97.   
  98.     /** 
  99.      * Remove an object from a cache model. 
  100.      *  
  101.      * @param cacheModel 
  102.      *            - the model to remove the object from. 
  103.      * @param key 
  104.      *            - the key to the object. 
  105.      * @return the removed object(?). 
  106.      */  
  107.     public Object removeObject(CacheModel cacheModel, Object key) {  
  108.         Object result = this.getObject(cacheModel, key);  
  109.         getCache(cacheModel).remove(key);  
  110.         return result;  
  111.     }  
  112.   
  113.     /** 
  114.      * Gets an EH Cache based on an iBatis cache Model. 
  115.      *  
  116.      * @param cacheModel 
  117.      *            - the cache model. 
  118.      * @return the EH Cache. 
  119.      */  
  120.     private Cache getCache(CacheModel cacheModel) {  
  121.         String cacheName = cacheModel.getId();  
  122.         Cache cache = cacheManager.getCache(cacheName);  
  123.         return cache;  
  124.     }  
  125.   
  126.     /** 
  127.      * Shut down the EH Cache CacheManager. 
  128.      */  
  129.     public void finalize() {  
  130.         if (cacheManager != null) {  
  131.             cacheManager.shutdown();  
  132.         }  
  133.     }  
  134.   
  135.     /** 
  136.      * Configure a cache controller. Initialize the EH Cache Manager as a 
  137.      * singleton. 
  138.      *  
  139.      * @param props 
  140.      *            - the properties object continaing configuration information. 
  141.      */  
  142.     @Override  
  143.     public void configure(Properties props) {  
  144.         String configLocation = props.getProperty(CONFIG_LOCATION);  
  145.         // if can not found ehcache.xml from configLocaion,  
  146.         // use default configure file.  
  147.         if (configLocation == null) {  
  148.             configLocation = DEFAULT_CONFIG_LOCATION;  
  149.         }  
  150.         URL url = getClass().getResource(configLocation);  
  151.         cacheManager = CacheManager.create(url);  
  152.     }  
  153. }  



这里默认在根目录下获取ehcache.xml文件,可以通过cacheModel配置进行修改。 

在SqlMapConfig.xml文件中配置一个别名,作为全局变量,供其余SqlMap使用。 

Xml代码     收藏代码
  1. <typeAlias  
  2.         alias="EHCACHE"  
  3.         type="com.ibatis.sqlmap.engine.cache.ehcache.EhCacheController" />  


顺便提一句,要使用缓存注意SqlMapConfig.xml文件中settings节点配置cacheModelsEnabledtrue 

Xml代码     收藏代码
  1. <settings  
  2.     cacheModelsEnabled="true"  
  3.     useStatementNamespaces="true"   
  4.     ...   
  5. />  


接下来,在SqlMap.xml文件中的cacheModel 

Xml代码     收藏代码
  1. <cacheModel  
  2.     id="cache"  
  3.     type="EHCACHE">  
  4. ...  
  5. </cacheModel>  


如果要变更ehcache.xml文件路径为/config/ehcache.xml,可以在上述节点中下入如下代码: 

Xml代码     收藏代码
  1. <property name="configLocation" value="/config/ehcache.xml" />   



然后,就可以通过ehcache.xml控制ehcache缓存了! 

举例说明iBatis SqlMap & ehcahce.xml,以免有些兄弟混淆! 

以Account类为示例,在SqlMap中的配置为: 

Xml代码     收藏代码
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE sqlMap  
  3.     PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"  
  4.     "http://ibatis.apache.org/dtd/sql-map-2.dtd">  
  5. <sqlMap  
  6.     namespace="Account">  
  7.     <cacheModel  
  8.         id="cache"  
  9.         type="EHCACHE">  
  10.         <flushInterval  
  11.             hours="1" />  
  12.         <!-- flush操作,需要指明 Namespace -->  
  13.         <flushOnExecute  
  14.             statement="Account.create" />  
  15.     </cacheModel>  
  16.     <typeAlias  
  17.         alias="account"  
  18.         type="org.zlex.acl.Account" />  
  19.     <resultMap  
  20.         id="accountMap"  
  21.         class="account">  
  22.         <result  
  23.             property="accountId"  
  24.             column="accountId" />  
  25.         <result  
  26.             property="accountName"  
  27.             column="accountName" />  
  28.         <result  
  29.             property="mail"  
  30.             column="mail" />  
  31.         <result  
  32.             property="realName"  
  33.             column="realName" />  
  34.         <result  
  35.             property="status"  
  36.             column="status" />  
  37.         <result  
  38.             property="lastLoginTime"  
  39.             column="lastLoginTime" />  
  40.     </resultMap>  
  41.     <select  
  42.         id="readByAccountName"  
  43.         parameterClass="string"  
  44.         resultMap="accountMap"  
  45.         cacheModel="cache">  
  46.         <![CDATA[ 
  47.             SELECT  
  48.                 accountId, 
  49.                 accountName, 
  50.                 mail, 
  51.                 realName, 
  52.                 status, 
  53.                 lastLoginTime 
  54.             FROM  
  55.                 acl_account 
  56.             WHERE  
  57.                 accountName = #accountName#  
  58.         ]]>  
  59.     </select>  
  60.     <insert  
  61.         id="create"  
  62.         parameterClass="account">  
  63.         <![CDATA[ 
  64.             INSERT INTO  
  65.                 acl_account( 
  66.                 accountName, 
  67.                 mail, 
  68.                 realName, 
  69.                 status, 
  70.                 lastLoginTime 
  71.                 )  
  72.             VALUES ( 
  73.                     #accountName#, 
  74.                     #mail#, 
  75.                     #realName#, 
  76.                     #status#, 
  77.                     #lastLoginTime# 
  78.                 ) 
  79.         ]]>  
  80.         <selectKey  
  81.             resultClass="long"  
  82.             keyProperty="accountId">  
  83.             <![CDATA[select LAST_INSERT_ID() as id ]]>  
  84.         </selectKey>  
  85.     </insert>  
  86. </sqlMap>  


注意: 

引用


<select  
id="readByAccountName"  
parameterClass="string"  
resultMap="accountMap"  
cacheModel="cache">  


这里的cacheModel="cache",对应的在ehcache.xml中就应该是: 

Xml代码     收藏代码
  1. <cache   
  2.     name="Account.cache"   
  3.     maxElementsInMemory="10000"   
  4.     eternal="false"  
  5.     maxElementsOnDisk="1000"   
  6.     overflowToDisk="true"   
  7.     timeToIdleSeconds="300"  
  8.     />  


因为,我使用了useStatementNamespaces="true"

package easyway.tbs.framework.cache;

import java.io.Serializable;

import java.util.Set;

/**

 * cache 通用接口

 *

 * @author longgangbai

 */

publicinterface Cache extends Serializable {

    public Object get(Object key);

    publicvoid put(Object key, Object value);

    publicvoid remove(Object key);

    publicvoid clear();

    publicint size();

    @SuppressWarnings("unchecked")

    public Set keys();

    @SuppressWarnings("unchecked")

    public Set values();

}

package easyway.tbs.framework.cache;

import easyway.tbs.framework.app.exceptions.SystemException;

/**

 * CacheManager提供和维护Cache生命周期实例

 *

 * @authorlonggangbai

 */

 

publicinterface CacheManager {

    /**

     * 根据指定的名称获取Cache实现,

     * 如果指定的名称的cache还不存,

     * 则以名称建立一个cache

     * 并返回cache对象

     *  

     * @param name 要获得的cache名称.

     * @return Cache 返回指定名称的cache实例   

     */

    public Cache getCache(String name)  throws SystemException;

    publicvoid destroy(String name) throws SystemException;

    }

package easyway.tbs.framework.cache;

import java.util.HashMap;

import java.util.Map;

import easyway.tbs.framework.app.exceptions.SystemException;

/**

 * 默认的内存缓存管理器

 *

 * @authorlonggangbai

 */

 

publicclass DefaultCacheManager implements CacheManager  {

 

    /**

     * DefaultCacheManager维护内存缓存对象

     */

    privatestaticfinal Map<String, Cache> caches = new HashMap<String, Cache>();

    /*

     * 获得指定的名称cache对象

     *

     * @see

     * easyway.tbs.framework.app.cache.CacheManager#getCache(java.lang.String)

     */

    public Cache getCache(String name) {

        if (name == null) {

            thrownew SystemException("cache-001", "缓存名称不能为空");

        }

        Cache cache;

        synchronized (caches) {

            cache = caches.get(name);

            if (cache == null) {

                cache = new SoftHashMapCache(name);

                caches.put(name, cache);

            }

        }

        return cache;

    }

 

    publicvoid destroy(String name) throws SystemException {

       

        synchronized (caches) {    

                caches.remove(name);

            }

        }

    }

     项目建议:实现Ibatis的缓存的扩展建议采用mechcache或者xmechcache的分布式缓存功能,mechcache为分布式的缓存,性能各方面的比较优越。使用OSCache可以参考Spring或者JforumCache的设计思路。

 

 

你可能感兴趣的:(spring,框架,cache,ibatis,项目管理)