1. 程式人生 > >cache快取整合---redis為例

cache快取整合---redis為例

分散式快取;

用redis(ecache,memacahe)

用任何一種快取只有結合多種快取操作才能實現利用快取,更新快取

(1)用標籤的話,清空和快取的標籤同時使用,即可控制重新整理快取的時機

http://tom-seed.iteye.com/blog/2104430

http://www.cnblogs.com/jianjianyang/p/4933016.html//////////////////////////(好)

 Spring Cache是作用在方法上的,其核心思想是這樣的:當我們在呼叫一個快取方法時會把該方法引數和返回結果作為一個鍵值對存放在快取中,

 等到下次利用同樣的引數來呼叫該方法時將不再執行該方法,而是直接從快取中獲取結果進行返回。所以在使用Spring   Cache的時候我們要保證我們快取的方法對於相同的方法引數要有相同的返回結果。

 使用Spring Cache需要我們做兩方面的事:1.宣告某些方法使用快取 2.配置Spring對Cache的支援(引數值最為key)

 值對比引數相同不相同,引數值相同就直接從快取中拿,引數不同就再查,不斷的存不同的引數

需要注意的是當一個支援快取的方法在物件內部被呼叫時是不會觸發快取功能的。@Cacheable可以指定三個屬性,value、key和condition。

屬性一 :value

    必須指定的,其表示當前方法的返回值是會被快取在哪個Cache上的,對應Cache的名稱,為ehcache.xml中的<cache name="myCache"/> 。其可以是一個Cache也可以是多個Cache,當需要指定多個Cache時其是一個數組。

屬性二 :key

    快取的Key,當我們沒有指定該屬性時,Spring將使用預設策略生成key(表示使用方法的引數型別及引數值作為key),key屬性是用來指定Spring快取方法的返回結果時對應的key的。該屬性支援SpringEL表示式。我們還可以自定義策略:自定義策略是指我們可以通過Spring的EL表示式來指定我們的key。這裡的EL表示式可以使用方法引數及它們對應的屬性。使用方法引數時我們可以直接使用“#引數名”或者“#p引數index”

    key的生成策略有兩種:一種是預設策略,一種是自定義策略

       ¹預設的key生成策略是通過KeyGenerator生成的,其預設策略如下:

            1.如果方法沒有引數,則使用0作為key。

            2.如果只有一個引數的話則使用該引數作為key。

            3.如果引數多餘一個的話則使用所有引數的hashCode作為key(這就是key值是一串hashzCode的原因)

        ²自定義策略是指我們可以通過Spring的EL表示式來指定我們的key。這裡的EL表示式可以使用方法引數及它們對應的屬性。使用方法引數時我們可以直接使用“#引數名”或者“#p引數index

屬性四 :allEntries(一個快取(value)中可以快取很多key對應的值)

    是boolean型別,表示是否需要清除快取中的所有元素。預設為false,表示不需要。當指定了allEntries為true時,Spring Cache將忽略指定的key。有的時候我們需要Cache一下清除所有的元素,這比一個一個清除元素更有效率。

              @CacheEvict(value="users", allEntries=true)

              public void delete(Integer id) {

                 System.out.println("delete user by id: " + id);

              }

屬性五 :beforeInvocation

    清除操作預設是在對應方法成功執行之後觸發的,即方法如果因為丟擲異常而未能成功返回時也不會觸發清除操作。使用beforeInvocation可以改變觸發清除操作的時間,當我們指定該屬性值為true時,Spring會在呼叫該方法之前清除快取中的指定元素。

             @CacheEvict(value="users", beforeInvocation=true)

             public void delete(Integer id) {

               System.out.println("delete user by id: " + id);

             }

注意我們也可以使用ehcache的去除策略最近使用(LRU)"策略,其它還有先入先出FIFO,最少使用LFU,較少使用LRU

基於註解配置:(使用不同的代理決定,標籤在介面上是否有用,是否只能作用在public方法上,是否類內部呼叫無效)(aop的代理方式:jdk,cglib(動態))aspectj靜態

       配置Spring對基於註解的Cache的支援,首先我們需要在Spring的配置檔案中引入cache名稱空間,其次通過<cache:annotation-driven />就可以啟用Spring對基於註解的Cache的支援。

<cache:annotation-driven/>(用不用代理---》什麼情況起作用(方法是否公有,內部呼叫是否起作用,是否介面處))

       <cache:annotation-driven/>有一個mode屬性,可選值有proxy和aspectj。預設是使用proxy。當mode為proxy時,只有快取方法在外部被呼叫的時候Spring Cache才會發生作用,

       這也就意味著如果一個快取方法在其宣告物件內部被呼叫時Spring Cache是不會發生作用的。而mode為aspectj時就不會有這種問題。

       另外使用proxy時,只有public方法上的@Cacheable等標註才會起作用,如果需要非public方法上的方法也可以使用Spring Cache時把mode設定為aspectj。(註解非公共方法,內部呼叫是否起作用)

       此外,<cache:annotation-driven/>還可以指定一個proxy-target-class屬性,表示是否要代理class,預設為false。(是否介面上起作用)

       我們前面提到的@Cacheable、@cacheEvict等也可以標註在介面上,這對於基於介面的代理來說是沒有什麼問題的

       ,但是需要注意的是當我們設定proxy-target-class為true或者mode為aspectj時,是直接基於class進行操作的,定義在介面上的@Cacheable等Cache註解不會被識別到,那對應的Spring 

       Cache也不會起作用了。

 <tx:annotation-driven/>(事務註解掃描)和<cache:annotation-driven/>(快取註解掃面)這個不同(哪種代理---->什麼情況(介面處))

 <tx:annotation-driven transaction-manager="transactionManager" 

                                       proxy-target-class="true"/>

  注意:proxy-target-class屬性值決定是基於介面的還是基於類的代理被建立。如果proxy-target-class 屬性值被設定為true,那麼基於類的代理將起作用(這時需要cglib庫)。如果proxy-target-class屬值被設定為false或者這個屬性被省略,那麼標準的JDK 基於介面的代理將起作用。

即使你未宣告 proxy-target-class="true" ,但執行類沒有繼承介面,spring也會自動使用CGLIB代理。

高版本spring自動根據執行類選擇 JDK 或 CGLIB 代理

http://blog.csdn.net/centre10/article/details/6847828

(2)配置檔案制定方法快取:

       需要注意的是<cache:annotation-driven/>只會去尋找定義在同一個ApplicationContext下的@Cacheable等快取註解。

http://haohaoxuexi.iteye.com/blog/2123030

http://haohaoxuexi.iteye.com/blog/2123030

快取和事務的方式,思想類似對比學習

比如都可基於xml,註解,用的代理決定什麼情況起作用

(3)key設計示例即問題:

//用jredis的方法的話,也是要清空和快取的方法結合使用,保證快取及時更新

@Cacheable註解也直接有序列化儲存實體的功能

@Cacheable("BasSpsxValueDaoImpl.getDefaultValue")

@Cacheable(value="TbClientLogServiceImpl.getLogList",key="#param.get('pageSize')")//map型別引數

@Cacheable(value="ChainDefinitionSectionMetaSource.getSectionService",key="#root.caches[0].name")//無引數就這樣處理

public Section getSectionService(String filterChainDefinitions) {

有引數不能用預設的要不然出錯

問題一:

maybe you are using named params on classes without debug info? --- key的欄位為空導致,無引數的用這個#root.caches[0].name,

有引數的一定用引數(不同引數不同結果)

//實體引數

@Cacheable(value="getMenuItems",key="'id='+#item.id")//用這種拼接的方式可以防止空值造成的這種錯誤,當然也可加個 condition="#articleComment.article != null "

public List<OpmMenuitem> getMenuItems(OpmMenuitem item) {

// TODO Auto-generated method stub

return opmMenuitemMapper.select(item);

}

@Cacheable(value="getMenuItems",key="'menufolderid='+#item.menufolderid")

public List<OpmMenuitem> getMenuItems(OpmMenuitem item) {

// TODO Auto-generated method stub

return opmMenuitemMapper.select(item);

}

問題二:

java.util.HashMap cannot be cast to com.esteel.system.bean.OpmUserRole

at com.esteel.system.controller.LoginController.login(LoginController.java:160)

java.util.HashMap cannot be cast to com.esteel.system.bean.OpmRolelimit,快取之後變成hashmap  //這種問題往往是直接用id等容易和其他key相同的值作為key,(自己的key被覆蓋)

在取快取的時候,去了其他型別的值list<bean>取的key對應list<HashMap>

List<OpmUserRole> ur=opmUserRoleService.getOpmUserRole(u);

@Override

@Cacheable(value="getOpmUserRole",key="#u.userid")

public List<OpmUserRole> getOpmUserRole(OpmUserRole u) {

// TODO Auto-generated method stub

return opmUserRoleMapper.select(u);

}

用下面的註解例子:(註解在@Server的實現類的公共方法最保險)

@Cacheable(value="TbClientLogServiceImpl.getLogList",key="'getLogList'+#param.get('pageSize')")

public PageInfo<TbClientLogVo> getLogList(Map<String, Object> param) {}//map型別

@Cacheable(value="getMenuItems",key="'menufolderid='+#item.menufolderid")

public List<OpmMenuitem> getMenuItems(OpmMenuitem item) {}//實體型別

@Cacheable(value="getRoleLimtContro",key="#root.caches[0].name")//無引數型別

public List<OpmRolelimitVo> getRoleLimtContro() {}

 @Cacheable(value="TbClientLogServiceImpl.getLogList",key="'getLogList'+#param.get('pageSize')+#param.get('pageNum')+#param.get('CUS_USER_ID')")

public PageInfo<TbClientLogVo> getLogList(Map<String, Object> param) {

http://www.iteye.com/problems/94305

Failed to deserialize payload

 class invalid for deserialization

(4)應用配置-快取配置:

<beans xmlns="http://www.springframework.org/schema/beans"

  xmlns:cache="http://www.springframework.org/schema/cache"

  xmlns:c="http://www.springframework.org/schema/c"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  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/>

<!-- redis快取管理器 -->

<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"

c:template-ref="jedisTemplate" /> //使用的快取型別

應用的話類似事務