<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    當(dāng)柳上原的風(fēng)吹向天際的時(shí)候...

    真正的快樂(lè)來(lái)源于創(chuàng)造

      BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
      368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks
    對(duì)一個(gè)成規(guī)模的系統(tǒng)來(lái)說(shuō),緩存總是不可或缺的一個(gè)環(huán)節(jié),甚至?xí)蔀橄到y(tǒng)成功的重要因素。

    從原理來(lái)講,緩存并不神秘,它本質(zhì)上只是一個(gè)哈希表,內(nèi)部包含許多提取關(guān)鍵字和緩存內(nèi)容的鍵值對(duì),當(dāng)有讀操作(如search)新的查詢到來(lái)時(shí),系統(tǒng)先到 這個(gè)哈希表中看看是否有同樣的關(guān)鍵字存在,是則取出對(duì)應(yīng)的值返回,否則進(jìn)行查詢,并把新的查詢條件和結(jié)果存儲(chǔ)進(jìn)哈希表,以便下次提取;當(dāng)有寫操作(如 add,delete,update)來(lái)臨時(shí),原則上說(shuō)現(xiàn)有緩存的內(nèi)容都存在了不確定性,那么簡(jiǎn)單的處理就是清空現(xiàn)有緩存。

    緩存器的位置可以放在具體要執(zhí)行的CRUD方法之前,當(dāng)然我個(gè)人是不提倡這種耦合子系統(tǒng)的做法,利用Java的動(dòng)態(tài)代理機(jī)制,我們可以把數(shù)據(jù)庫(kù)訪問(wèn)和緩存 兩部分分離開來(lái),而Spring提供的ProxyFactoryBean和Interceptor正好給我們提供了現(xiàn)成的便利,使我們不需要再重復(fù)的發(fā)明 車輪。這樣做的最大好處是解耦子系統(tǒng),因?yàn)轳詈鲜菍?dǎo)致系統(tǒng)癱瘓的重大因素,所以我們必須盡量避免,隨時(shí)提防.

    請(qǐng)看具體來(lái)說(shuō)是怎么實(shí)現(xiàn)緩存的,下面是需要為之提供緩存服務(wù)的TmpServiceImpl類及其接口:
    TmpServiceImpl類:
    public class TmpServiceImpl extends BaseService implements IService{
      
    /**
       * 添加一個(gè)Tmp對(duì)象到數(shù)據(jù)庫(kù)
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String add(String[] args) throws Exception{
        String name
    =args[0];
        
    int age=Integer.parseInt(args[1]);
        
    float salary=Float.parseFloat(args[2]);
        
        
    // 同名檢測(cè)
        if(hasSameName(name)){
          
    throw new BreakException("已經(jīng)有和"+name+"同名的對(duì)象存在了.");
        }
        
        Tmp tmp
    =new Tmp(name,age,salary);
        dao.create(tmp);
        
        
    return tmp.toXML();
      }
      
      
    /**
       * 將TMP對(duì)象的信息組合成一個(gè)字符串返回
       * 
       * 說(shuō)明:要修改此方法請(qǐng)與何楊商議,請(qǐng)勿自行修改!
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String getInfoById(String[] args) throws Exception{
        String id
    =args[0];
        
        Tmp tmp
    =(Tmp)getObjById(id);
        
        
    if(tmp==null){
          
    throw new BreakException("找不到Id'"+id+"'對(duì)應(yīng)的Tmp對(duì)象.");
        }
        
        StringBuilder sb
    =new StringBuilder();
        
        sb.append(
    "姓名:"+tmp.getName()+""r"n");
        sb.append(
    "年齡:"+tmp.getAge()+""r"n");
        sb.append(
    "薪水:"+tmp.getSalary()+""r"n");
        sb.append(
    "添加時(shí)間:"+tmp.getAddTime()+""r"n");
        sb.append(
    "更新時(shí)間:"+tmp.getRefreshTime()+""r"n");
        
        
    return sb.toString();
      }
      
      
    /**
       * 按ID取得一個(gè)Tmp對(duì)象
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String getById(String[] args) throws Exception{
        String id
    =args[0];
        
        Tmp tmp
    =(Tmp)getObjById(id);
        
        
    if(tmp==null){
          
    throw new BreakException("找不到Id'"+id+"'對(duì)應(yīng)的Tmp對(duì)象.");
        }
        
        
    return tmp.toXML();
      }
      
      
    /**
       * 按薪水來(lái)查詢Tmp對(duì)象
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String searchBySalary(String[] args)throws Exception{
        
    float salary=Float.parseFloat(args[0]);
        
        StringBuilder sb 
    = new StringBuilder();
        sb.append(
    " from " + domainClass + " d where d.valid=true and ");
        sb.append(
    " d.salary >='"+salary+"" );
        sb.append(
    " order by id asc ");
        
        String hql
    =sb.toString();
        
    return convertListToXml(dao.search(hql));
      }
      
      
    /**
       * 按ID來(lái)更新一個(gè)Tmp對(duì)象
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String update(String[] args)throws Exception{
        String id
    =args[0];
        String name
    =args[1];
        
    int age=Integer.parseInt(args[2]);
        
    float salary=Float.parseFloat(args[3]);
        
        Tmp tmp
    =(Tmp)getObjById(id);    
        
    if(tmp==null){
          
    throw new BreakException("找不到Id'"+id+"'對(duì)應(yīng)的Tmp對(duì)象.");
        }
        
        tmp.setName(name);
        tmp.setAge(age);
        tmp.setSalary(salary);
        dao.update(tmp);
        
        
    return tmp.toXML();
      }
      
      
    /**
       * 刪除一個(gè)對(duì)象
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String delete(String[] args) throws Exception{
        String id
    =args[0];
        
        Tmp tmp
    =(Tmp)getObjById(id);    
        
    if(tmp==null){
          
    throw new BreakException("找不到Id'"+id+"'對(duì)應(yīng)的Tmp對(duì)象.");
        }
        
        dao.delete(tmp);
        
        
    return tmp.toXML();
      }
      
      
    /**
       * 分頁(yè)搜索
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String pagedSearchBy(String[] args) throws Exception{
        
        
    int currentPage=Integer.parseInt(args[0]);  // 當(dāng)前頁(yè)
        int pageSize=Integer.parseInt(args[1]);   // 頁(yè)面記錄數(shù)
        String name=args[2];            // 姓名
        String salaryFrom=args[3];          // 薪水起點(diǎn)
        String salaryTo=args[4];          // 薪水終點(diǎn)
        String ageFrom=args[5];           // 年齡起點(diǎn)
        String ageTo=args[6];           // 年齡終點(diǎn)
        
        
    // 組合Sql語(yǔ)句
        StringBuilder sb = new StringBuilder();
        sb.append(
    " from " + domainClass + " d where d.valid=true  ");
        
        
    if(StringUtils.isNotBlank(name)){
          sb.append(
    " and d.name like '%"+name+"%' " );
        }
        
        
    if(StringUtils.isNotBlank(salaryFrom)){
          sb.append(
    " and d.salary >='"+salaryFrom+"" );
        }
        
    if(StringUtils.isNotBlank(salaryTo)){
          sb.append(
    " and d.salary <'"+salaryTo+"" );
        }
        
        
    if(StringUtils.isNotBlank(ageFrom)){
          sb.append(
    " and d.age >='"+ageFrom+"" );
        }
        
    if(StringUtils.isNotBlank(ageTo)){
          sb.append(
    " and d.age <'"+ageTo+"" );
        }
        
        sb.append(
    " order by id asc ");   
        String hql
    =sb.toString();
        
        
    // 取得分頁(yè)查詢結(jié)果
        return getPagedSearchResultInXML(hql,currentPage,pageSize);
      }

      @Override
      
    public String search(String[] args) throws Exception {
        
    return null;
      }
    }

    IService接口:
    public interface IService{
      
    /**
       * 解析參數(shù)數(shù)組,組合成一個(gè)領(lǐng)域?qū)ο螅缓筇砑拥綌?shù)據(jù)庫(kù)(寫方法)
       * 
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String add(String[] args) throws Exception;
      
      
    /**
       * 解析參數(shù)數(shù)組,更新領(lǐng)域?qū)ο蟮囊粋€(gè)或多個(gè)屬性,然后更新數(shù)據(jù)庫(kù)中的對(duì)應(yīng)記錄
       * 
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String update(String[] args)throws Exception;
      
      
    /**
       * 解析參數(shù)數(shù)組得到要?jiǎng)h除的領(lǐng)域?qū)ο蟮腎d,然后根據(jù)它刪除數(shù)據(jù)庫(kù)中的對(duì)應(yīng)記錄
       * 
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String delete(String[] args) throws Exception;
      
      
    /**
       * 解析參數(shù)數(shù)組得到要取得的領(lǐng)域?qū)ο蟮腎d,然后根據(jù)它渠道數(shù)據(jù)庫(kù)中的對(duì)應(yīng)記錄
       * 
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String getById(String[] args) throws Exception;
      
      
    /**
       * 按條件進(jìn)行分頁(yè)查詢
       * 注意這里的條件最好寫全,最好根據(jù)數(shù)組內(nèi)容走不同的分支,不要寫各種各樣的查詢函數(shù),這樣不方便緩存的處理
       * 
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String pagedSearchBy(String[] args) throws Exception;
      
      
    /**
       * 按條件進(jìn)行查詢,除了不分頁(yè)要求和上面函數(shù)(pagedSearchBy)一致
       * 
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String search(String[] args) throws Exception;
      
      
    /**
       * 按ID取得信息
       * 
       * 
    @param args
       * 
    @return
       * 
    @throws Exception
       
    */
      
    public String getInfoById(String[] args) throws Exception;
    }

    可以看出來(lái),上面的服務(wù)類是直接走到數(shù)據(jù)庫(kù)操作記錄的,而我們需要在它的函數(shù)執(zhí)行之前就讓緩存發(fā)揮左右,因此,我們需要引入 ProxyFactoryBean和Interepter的幫助,在TmpServiceImpl類的實(shí)際方法運(yùn)行前檢索緩存。這需要進(jìn)行一定的配置:
      <!-- Tmp對(duì)象服務(wù)實(shí)現(xiàn)類類方法攔截器(一) -->
        
    <bean id="tmpServiceMethodInterceptor" class="com.***.service.interceptor.ServiceMethodInterceptor"/>
        
        
    <!-- Tmp對(duì)象服務(wù)實(shí)現(xiàn)類(二) -->
        
    <bean id="TmpServiceImpl" class="com.***.service.TmpServiceImpl">
            
    <property name="domainClass">
                
    <value>Tmp</value>
            
    </property>
            
    <property name="dao">
                
    <ref bean="dao"/>
            
    </property>
            
    <property name="transactionTemplate">
                
    <ref bean="transactionTemplate"/>
            
    </property>
        
    </bean>
        
        
    <!-- 對(duì)外的TmpService,實(shí)際上是TmpServiceImpl的代理(三) -->
        
    <bean id="TmpService" class="org.springframework.aop.framework.ProxyFactoryBean">
            
    <property name="proxyInterfaces">
                
    <value>com.***.service.base.IService</value>
            
    </property>
            
    <property name="interceptorNames">
                
    <list>
                    
    <value>tmpServiceMethodInterceptor</value>
                
    </list>
            
    </property>
            
    <property name="target">
                
    <ref bean="TmpServiceImpl"/>
            
    </property>
        
    </bean>

    這樣就可以了,下面是com.***.service.interceptor.ServiceMethodInterceptor類的代碼,應(yīng)該很好理解:
    public class ServiceMethodInterceptor implements MethodInterceptor{
        
    // 日志記錄器
        private    static Logger logger = Logger.getLogger(ServiceMethodInterceptor.class);
        
        
    // 作為緩存的哈希表
        private Map<String,Object> cacheMap=new Hashtable<String,Object>();

        @Override
        
    public Object invoke(MethodInvocation invocation) throws Throwable {
            String className
    =invocation.getClass().getName();
            String mothodName
    =invocation.getMethod().getName();
            logger.info(
    "類'"+className+"'的方法'"+mothodName+"'將得到調(diào)用!");
            
            
    if(mothodName.contains("add"|| mothodName.contains("update"|| mothodName.contains("delete") ){
                
    // 寫方法來(lái)了,這意味著數(shù)據(jù)變更了,緩存可能不可靠,為安全起見需要重新來(lái)過(guò)
                cacheMap.clear();
                
                Object result
    =invocation.proceed();
                logger.info(
    "類'"+className+"'的方法'"+mothodName+"'調(diào)用完畢!");
                
                
    return result;
            }
            
    else{
                
    // 來(lái)的是讀方法
                
                
    // 通過(guò)組合方法名和參數(shù)來(lái)得到key
                StringBuffer sb=new StringBuffer();
                sb.append(mothodName
    +";");
                
                Object[] arr
    =invocation.getArguments();
                String[] arr2
    =(String[])arr[0];// 這一步的轉(zhuǎn)化是很重要的
                for(Object obj:arr2){
                    sb.append(obj
    +",");
                }
                
                String key
    =sb.toString();
                
                
    // 拿Key查看緩存中是否有內(nèi)容,有則直接返回即可
                if(cacheMap.containsKey(key)){
                    logger.info(
    "直接得到緩存中的結(jié)果!");
                    
    return cacheMap.get(key);
                }
                
    else{
                    Object result
    =invocation.proceed();
                    
                    cacheMap.put(key, result);
                    logger.info(
    "類'"+className+"'的方法'"+mothodName+"'調(diào)用完畢!");
                    
                    
    return result;
                }
            }
        }
    }

    之所以使用MethodInterceptor是因?yàn)樵谄渲锌梢孕薷姆祷氐慕Y(jié)果,在上面出現(xiàn)的
    Object result=invocation.proceed();           
    return result;
    實(shí)際就是對(duì)TempServiceImpl函數(shù)執(zhí)行的調(diào)用,result就是返回結(jié)果,它是可以改變的。因此,如果緩存中有對(duì)應(yīng)內(nèi)容,取出直接返回,沒(méi)有的話調(diào)用這兩句進(jìn)行老實(shí)的數(shù)據(jù)庫(kù)操作即可。

    到這里,緩存已經(jīng)可以使用了,當(dāng)然,它還很不完善,在鍵的設(shè)計(jì)和簡(jiǎn)化,如果數(shù)據(jù)過(guò)多時(shí)的硬盤暫存,數(shù)據(jù)過(guò)期,寫操作對(duì)緩存影響的精細(xì)化上都可以下一番工夫,這些我們?nèi)蘸笤偬接懓伞?
    posted on 2010-05-24 15:10 何楊 閱讀(635) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 最近2019中文字幕免费看最新| 免费看黄网站在线看 | 2019中文字幕免费电影在线播放 | 亚洲AV成人一区二区三区观看| 亚洲狠狠成人综合网| 亚洲 日韩 色 图网站| 亚洲va精品中文字幕| 亚洲精品国产精品国自产网站| 亚洲成a人片在线网站| 久久精品国产亚洲av麻豆图片| 亚洲国产成人久久| 中文字幕在线免费看线人| 一个人看www免费高清字幕| 精品久久久久久无码免费| 中文字幕在线免费播放| 少妇性饥渴无码A区免费| 嫩草成人永久免费观看| 精品一区二区三区无码免费视频| 最近免费中文字幕大全免费版视频| 在线免费中文字幕| 久久99九九国产免费看小说| 女人18毛片水最多免费观看| 在线免费观看韩国a视频| 亚洲av中文无码| 亚洲色欲色欲www在线丝| 亚洲国产成人私人影院| 亚洲欧洲日本天天堂在线观看| 久久精品国产亚洲AV久| 国产亚洲视频在线观看| ssswww日本免费网站片| 久久精品视频免费播放| 18国产精品白浆在线观看免费| 夜夜爽免费888视频| 亚洲精品国产精品乱码不卡| 亚洲美女又黄又爽在线观看| 亚洲一二成人精品区| 2020亚洲男人天堂精品| 日韩免费码中文在线观看| 免费91最新地址永久入口 | 日本在线观看免费高清| 日韩a级无码免费视频|