spring3 和ehcache 整合


     公司项目有些地方需要用到缓存,考虑到需要缓存的东西不多,还没到使用redis memcached 之类的地步,先选择轻量级的ehcache即可。

项目用到的是mybatis ,本来想用mybatis整合ehcache,但是后来发现一个比他更好点的解决方案,spring 3.1之后就可以整合cache了。

并且使用自带注解去进行缓存控制非常方便,松耦合。


先介绍一下几个用到的注解


@Cacheable:负责将方法的返回值加入到缓存中
@CacheEvict:负责清除缓存
@Cacheable 支持如下几个参数:
value:缓存位置名称,不能为空,如果使用EHCache,就是ehcache.xml中声明的cache的name
key:缓存的key,默认为空,既表示使用方法的参数类型及参数值作为key,支持SpEL
condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持SpEL

 //将缓存保存进andCache,并使用参数中的userId加上一个字符串(这里使用方法名称)作为缓存的key
 @Cacheable(value="andCache",key="#userId + 'findById'")
public SystemUser findById(String userId) {
	SystemUser user = (SystemUser) dao.findById(SystemUser.class, userId);
	 return user ;
 }
 //将缓存保存进andCache,并当参数userId的长度小于32时才保存进缓存,默认使用参数值及类型作为缓存的key
@Cacheable(value="andCache",condition="#userId.length < 32")
	 public boolean isReserved(String userId) {
	 System.out.println("hello andCache"+userId);
	 return false;
 }
@CacheEvict 支持如下几个参数:
value:缓存位置名称,不能为空,同上
key:缓存的key,默认为空,同上
condition:触发条件,只有满足条件的情况才会清除缓存,默认为空,支持SpEL
allEntries:true表示清除value中的全部缓存,默认为false


//清除掉指定key的缓存
@CacheEvict(value="andCache",key="#user.userId + 'findById'")
public void EvictUserRole(SystemUser user) {
System.out.println("hello andCache delete"+user.getUserId());
}
//清除掉全部缓存
@CacheEvict(value="andCache",allEntries=true)
public final void EvictUsers(String[] reservedUsers) {
System.out.println("hello andCache deleteall");
}


接下来是具体整合步骤:

一,引入jar包  ehcache-core-2.4.4.jar     ehcache-spring-annotations-1.2.0.jar

链接:http://pan.baidu.com/s/1mgYpZLI 密码:op7j

二,配置文件整合

需要spring 容器内支持cache

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/cache 
    http://www.springframework.org/schema/cache/spring-cache.xsd">
        
    <cache:annotation-driven />
    
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
	<!-- EhCache library setup -->
	<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="classpath:ehcache.xml" p:shared="true"/>
    
    
</beans>

需要一个ehcache的缓存策略文件。

<?xml version="1.0" encoding="UTF-8"?>  
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false">
    <diskStore path="java.io.tmpdir"/> 
   
    <defaultCache    
            maxElementsInMemory="3000"    
            eternal="true"    
            timeToIdleSeconds="3600"    
            timeToLiveSeconds="3600"    
            overflowToDisk="true"    
            diskPersistent="false"    
            diskExpiryThreadIntervalSeconds="100"    
            memoryStoreEvictionPolicy="LRU"    
            />    
    <cache name="shopCache"    
           maxElementsInMemory="3000"    
            eternal="true"    
            timeToIdleSeconds="3600"    
            timeToLiveSeconds="3600"    
            overflowToDisk="true"    
            diskPersistent="false"    
            diskExpiryThreadIntervalSeconds="100"    
            memoryStoreEvictionPolicy="LRU"     
            /> 
<!-- 
name: cache的名字,用来识别不同的cache,必须惟一。   
maxElementsInMemory: 内存管理的缓存元素数量最大限值。   
maxElementsOnDisk: 硬盘管理的缓存元素数量最大限值。默认值为0,就是没有限制。   
eternal: 设定元素是否持久话。若设为true,则缓存元素不会过期。   
overflowToDisk: 设定是否在内存填满的时候把数据转到磁盘上。
timeToIdleSeconds: 设定元素在过期前空闲状态的时间,只对非持久性缓存对象有效。默认值为0,值为0意味着元素可以闲置至无限长时间。   
timeToLiveSeconds: 设定元素从创建到过期的时间。其他与timeToIdleSeconds类似。   
diskPersistent: 设定在虚拟机重启时是否进行磁盘存储,默认为false.(我的直觉,对于安全小型应用,宜设为true)。   
diskExpiryThreadIntervalSeconds: 访问磁盘线程活动时间。   
diskSpoolBufferSizeMB: 存入磁盘时的缓冲区大小,默认30MB,每个缓存都有自己的缓冲区。   
memoryStoreEvictionPolicy: 元素逐出缓存规则。共有三种,Recently Used (LRU)最近最少使用,为默认。 First In First Out (FIFO),先进先出。Less Frequently Used(specified as LFU)最少使用  
--> 
</ehcache>


三,代码加注解

package com.shiquanjiumei.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.shiquanjiumei.bean.Shop;
import com.shiquanjiumei.bean.ShopMac;
import com.shiquanjiumei.dao.ShopDao;
import com.shiquanjiumei.service.ShopService;
import com.shiquanjiumei.util.ConstantUtils;
import com.shiquanjiumei.util.PageView;


@Transactional
@Service("shopService")
public class ShopServiceImpl implements ShopService{

	@Autowired
	private ShopDao shopDao;
	
	@Cacheable(value="shopCache",key="'UserMenuKey3_queryShopsByShopNums'")
	@Override
	public List<Shop> queryShopsByShopNums(String[] shopNums) {
		List<Shop> shopList = new ArrayList<Shop>();
		List<Shop> shops = new ArrayList<Shop>();
		
	    try {
	    		shopList = shopDao.getShopsByShopNums(shopNums);
	    		for(Shop shop :shopList){
	    			if (!StringUtils.isEmpty(shop.getImageUrl())) {
	    				shop.setImageUrl(ConstantUtils.IMG_URL+shop.getImageUrl()); //设置店铺Logo地址
	    				shops.add(shop);
					}
	    			
	    		}
	    		//shopList = shopDao.getShopsByShopNumsDisable(shopNums);
	    	
		} catch (Exception e) {
            e.printStackTrace();
		}
	    return shops; 
	}
	@Cacheable(value="shopCache",key="'UserMenuKey1'+#string")
	@Override
	public Shop queryShopByShopNum(String string) {
		Shop shop = new Shop();
		try {
			shop = shopDao.queryShopsByShopNum(string);
			if(shop!=null){
				shop.setImageUrl(ConstantUtils.IMG_URL+shop.getImageUrl()); 
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return shop;
	}
	@Cacheable(value="shopCache",key="'UserMenuKey2'+#userid")
	@Override
	public List<Shop> getShopsByShopNumsDisable(PageView pageView,
			String[] macNumArray) {
		List<Shop> shopList = new ArrayList<Shop>();
		List<Shop> shops = new ArrayList<Shop>();
	    try {
	    		shopList = shopDao.getShopsByShopNumsDisable(pageView,macNumArray);
	    		for(Shop shop :shopList){
	    			if (!StringUtils.isEmpty(shop.getImageUrl())) {
	    				shop.setImageUrl(ConstantUtils.IMG_URL+shop.getImageUrl()); //设置店铺Logo地址
	    				shops.add(shop);
					}
	    			
	    		}
	    		//shopList = shopDao.getShopsByShopNumsDisable(shopNums);
	    	
		} catch (Exception e) {
            e.printStackTrace();
		}
	    return shops; 
	}
	@CacheEvict(value="shopCache",allEntries=true)
	@Override
	public void add(Shop shop,List<ShopMac> shopMacList) {
		shopDao.add(shop);
		//shopDao.deleteShopMacByShopNum(shop.getShopNum());
		shopDao.addShopMac(shopMacList);
	}
	
	/**
	 * 上传店铺Logo
	 * @param shop
	 */
	@CacheEvict(value="shopCache",allEntries=true)
	@Override 
	public String uploadShopLogo(Shop shop){
		int count = 0;
		String logoImageUrlOld = ""; //存放店铺原Logo路径
		Shop shopOld = new Shop();
		try {
			String shopNum = shop.getShopNum(); //获取店铺编号
			shopOld = shopDao.getShopByShopNum(shopNum);
			if (null != shopOld) {
				logoImageUrlOld = shopOld.getImageUrl(); //获取店铺原Logo路径
				count = shopDao.updateShopLogo(shop); //上传店铺新的Logo
				if(count>0){ //上传成功
					return logoImageUrlOld; //返回店铺原Logo路径
				}
			}
		} catch (Exception e) { 
           e.printStackTrace();
		}
		return "";
	}
	@CacheEvict(value="shopCache",allEntries=true)
	@Override
	public int updateShop(Shop shop,List<ShopMac> shopMacList) {
		int count = 0;
		try {
			count = shopDao.updateShop(shop); //更新店铺信息
			shopDao.deleteShopMacByShopNum(shop.getShopNum()); //根据店铺编号删除原店铺Mac
			shopDao.addShopMac(shopMacList); //添加店铺Mac
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return count;
	}

	@Override
	public void checkShop(Shop shop) {
        shopDao.checkShop(shop);	
        
	}

	@Override
	public PageView query(PageView pageView, Shop shop) {
		List<Shop> shopList = shopDao.query(pageView, shop);
		pageView.setRecords(shopList);
		return pageView;
	}

	@Override
	public Shop getById(String id) {
		
		return shopDao.getById(id);
	}

	@Override
	public void checkShopBatchAgree(List<String> checkList) {

		try {
			shopDao.checkShopBatchAgree(checkList);
		} catch (Exception e) {
           e.printStackTrace();
		}
		
	}

	@Override
	public void checkShopBatchReject(List<String> checkList) {

		try {
			shopDao.checkShopBatchReject(checkList);
		} catch (Exception e) {
           e.printStackTrace();
		}
	}
	@CacheEvict(value="shopCache",allEntries=true)
	@Override
	public int deletebyShopNum(String shopNum) {
		int count = 0;
		try {
			count = shopDao.deletebyShopNum(shopNum);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return count;
	}
	@CacheEvict(value="shopCache",allEntries=true)
	@Override
	public int isRecommend(Shop shop) {

		int count = 0;
		try {
			count = shopDao.isRecommend(shop);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return count;
	}
	@CacheEvict(value="shopCache",allEntries=true)
	@Override
	public void deleteBatch(String[] ids) {
		try {
			//将id数组转为list
			List<String> idList = Arrays.asList(ids); 
			//将ids放入Map
			Map<String,Object> idsMap = new HashMap<String,Object>();
			idsMap.put("idList", idList);
			
			//根据ids批量查询 获得shopNum
			List<String> shopNums = shopDao.getShopNumsByids(idsMap);
			
			shopDao.deleteBatch(ids); //根据店铺Id批量删除店铺信息     t_shop表
			shopDao.deleteShopMacByShopNums(shopNums); //根据店铺shopNum批量删除店铺Mac信息   t_shop_mac表  根据shopNum删除
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	

}







四,测试

第一次调用查询的方法,发现sql被执行了

第二次调用查询的方法,发现sql没执行,但是数据依然存在,证明被缓存了。

第三次调用删除的方法,清除缓存。

第四次调用查询的方法,sql又被执行了,证明删除方法带动清除了缓存,保证数据同步。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值