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又被執行了,證明刪除方法帶動清除了緩存,保證數據同步。


發佈了75 篇原創文章 · 獲贊 71 · 訪問量 49萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章