<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      iBATIS緩存實現分析[轉]

      為了提高應用程序性能,一種比較通用的方法是使用緩存技術來減少與數據庫之間的交互。緩存技術是一種“以空間換時間”的設計理念,利用內存空間資源來提高數據檢索速度的有效手段之一。

           iBATIS以一種簡單、易用、靈活的方式實現了數據緩存。下面,首先看一下iBATIS關于緩存部分的核心類圖:

      iBATIS緩存核心類圖

           關于這些類的用途,在注釋中做了比較概括性的說明,下面就來仔細的講一下這些類的用途以及它們是如何工作的。

           在iBATIS中,可以配置多個緩存,每個cacheModel的配置對應一個CacheModel類的一個對象。其中包括id等配置信息。iBATIS通過這些配置信息來定義緩存管理的行為。

           緩存的目的是為了能夠實現數據的高速檢索。在程序中,數據是用對象表示的;為了能夠檢索到以緩存的數據對象,每個數據對象必須擁有一個唯一標識,在iBATIS中,這個唯一標識用CacheKey來表示。

           那么,緩存的數據保存到什么地方了呢?如何實現數據的快速檢索呢?答案在CacheController的實現類中。每個CacheController中都有一個Map類型的屬性cache來保存被緩存的數據,其中key為CacheKey類型,value為Object類型;需要關注的是CacheKey對象的hashCode的生成算法,每次調用CacheKey對象的update方法時,都會更新它的hashCode值,關于hashCode值的計算方法后續在給出詳細說明。

           在擁有了數據緩存區后,就可以向其中存放數據和檢索數據了。在iBATIS中,有多種的緩存管理策略,也可以自定義緩存管理策略。

           關于緩存的功能,主要有兩種類型:一種是對外提供的功能:數據存儲和數據檢索;另外一種是內部管理的功能:緩存對象標識的生成,緩存區刷新,數據檢索算法等。下面就逐一介紹這些功能的代碼實現。

           1. 數據存儲

               首先看一下CacheModel中的putObject方法是如何實現的

      1. public void putObject(CacheKey key, Object value) {  
      2.     if (null == value) value = NULL_OBJECT;  
      3.     //關于緩存的操作,需要互斥  
      4.     synchronized ( this )  {  
      5.      if (serialize && !readOnly && value != NULL_OBJECT) {  
      6.        //需要序列化,并且非只讀,則需要將緩存對象序列化到內存,以供后續檢索使用  
      7.         //readOnly為false時,不能直接將對象引用直接返回個客戶程序  
      8.        try {  
      9.          ByteArrayOutputStream bos = new ByteArrayOutputStream();  
      10.          ObjectOutputStream oos = new ObjectOutputStream(bos);  
      11.          oos.writeObject(value);  
      12.          oos.flush();  
      13.          oos.close();  
      14.          value = bos.toByteArray();  
      15.        } catch (IOException e) {  
      16.          throw new RuntimeException("Error caching serializable object.  Cause: " + e, e);  
      17.        }  
      18.      }  
      19.      //如果執行了內存序列化,則保存的是它的字節數組  
      20.      controller.putObject(this, key, value);  
      21.      if ( log.isDebugEnabled() )  {  
      22.        log("stored object"true, value);  
      23.      }  
      24.    }  
      25.  }  

             因為真正緩存數據對象的地方是在CacheController中,所以CacheModel的putObject方法中會調用CacheController的putObject方法執行真正的數據存儲。由于不同的CacheController實現的緩存管理方式不同,所以putObject實現也各不相同。下面分別介紹不同的CacheController實現的putObject方法

            1) FifoCacheController

      1. public void putObject(CacheModel cacheModel, Object key, Object value) {  
      2.   //保存到Map中  
      3.   cache.put(key, value);  
      4.   //保存key到keyList  
      5.   keyList.add(key);  
      6.   //如果當前key的數量大于緩存容量時,移除keyList和cache中的第一個元素,達到先進先出的目的  
      7.   if (keyList.size() > cacheSize) {  
      8.     try {  
      9.       Object oldestKey = keyList.remove(0);  
      10.       cache.remove(oldestKey);  
      11.     } catch (IndexOutOfBoundsException e) {  
      12.       //ignore  
      13.     }  
      14.   }  
      15. }  

             2)LruCacheController

      1. public void putObject(CacheModel cacheModel, Object key, Object value) {  
      2.   cache.put(key, value);  
      3.   keyList.add(key);  
      4.   if (keyList.size() > cacheSize) {  
      5.     try {  
      6.       //取得keyList中的第一個元素作為最近最少用的key,為什么呢?  
      7.        //這個問題等到講解它的getObject方法時別會知曉  
      8.       Object oldestKey = keyList.remove(0);  
      9.       cache.remove(oldestKey);  
      10.     } catch (IndexOutOfBoundsException e) {  
      11.       //ignore  
      12.     }  
      13.   }  
      14. }  

            3)MemoryCacheController

      1. public void putObject(CacheModel cacheModel, Object key, Object value) {  
      2.   Object reference = null;  
      3.   //根據配置創建響應的引用類型,此種緩存管理方式完全交給jvm的垃圾回收器來管理  
      4.    //創建好引用后,將數據對象放入到引用中  
      5.   if (referenceType.equals(MemoryCacheLevel.WEAK)) {  
      6.     reference = new WeakReference(value);  
      7.   } else if (referenceType.equals(MemoryCacheLevel.SOFT)) {  
      8.     reference = new SoftReference(value);  
      9.   } else if (referenceType.equals(MemoryCacheLevel.STRONG)) {  
      10.     reference = new StrongReference(value);  
      11.   }  
      12.   //在緩存中保存引用  
      13.   cache.put(key, reference);  
      14. }  

            4)OSCacheController

            這個緩存管理使用了OSCache來管理緩存,這里就不做仔細的介紹了。

           2. 數據檢索

           在數據被放置到緩存區中以后,程序需要根據一定的條件進行數據檢索。首先看一下CacheModel類的getObject方法是如何檢索數據的

      1. public Object getObject(CacheKey key) {  
      2.     Object value = null;  
      3.   //互斥訪問緩沖區  
      4.   synchronized (this) {  
      5.     if (flushInterval != NO_FLUSH_INTERVAL  
      6.         && System.currentTimeMillis() - lastFlush > flushInterval) {  
      7.       //如果到了定期刷新緩沖區時,則執行刷新  
      8.       flush();  
      9.     }  
      10.     //根據key來從CacheController中取得數據對象  
      11.     value = controller.getObject(this, key);  
      12.     if (serialize && !readOnly &&  
      13.             (value != NULL_OBJECT && value != null)) {  
      14.       //如果需要序列化,并且非只讀,則從內存中序列化出一個數據對象的副本  
      15.       try {  
      16.         ByteArrayInputStream bis = new ByteArrayInputStream((byte[]) value);  
      17.         ObjectInputStream ois = new ObjectInputStream(bis);  
      18.         value = ois.readObject();  
      19.         ois.close();  
      20.       } catch (Exception e) {  
      21.         throw new RuntimeException("Error caching serializable object.  Be sure you're not attempting to use " +  
      22.                                          "a serialized cache for an object that may be taking advantage of lazy loading.  Cause: " + e, e);  
      23.       }  
      24.     }  
      25.     //下面的兩個操作是用來計算緩存區數據檢索的命中率的  
      26.     //對于緩沖區的數據檢索請求加一操作  
      27.     requests++;  
      28.     //如果檢索到數據,則命中數加一  
      29.     if (value != null) {  
      30.       hits++;  
      31.     }  
      32.     if ( log.isDebugEnabled() )  {  
      33.         if ( value != null )  {  
      34.           log("retrieved object"true, value);  
      35.         }  
      36.         else  {  
      37.             log("cache miss"falsenull);  
      38.         }  
      39.     }  
      40.   }  
      41.   return value;  
      42. }  

          真正的數據檢索操作是在CacheController的實現類中進行的,下面就分別來看一下各個實現類是如何檢索數據的。

           1) FifoCacheController

      1. public Object getObject(CacheModel cacheModel, Object key) {  
      2.   //直接從Map中取得  
      3.   return cache.get(key);  
      4. }  

           2) LruCacheController

      1. public Object getObject(CacheModel cacheModel, Object key) {  
      2.   Object result = cache.get(key);  
      3.   //因為這個key被使用了,如果檢索到了數據,則將其移除并重新放置到隊尾  
      4.    //這樣的目的就是保持最近使用的key放在隊尾,而對頭為最近未使用的  
      5.    //如果沒有檢索到對象,則直接將該key移除  
      6.   keyList.remove(key);  
      7.   if (result != null) {  
      8.     keyList.add(key);  
      9.   }  
      10.   return result;  
      11. }  

           3) MemoryCacheController

      1. public Object getObject(CacheModel cacheModel, Object key) {  
      2.   Object value = null;  
      3.   //取得引用對象  
      4.   Object ref = cache.get(key);  
      5.   if (ref != null) {  
      6.     //從引用對象中取得數據對象  
      7.     if (ref instanceof StrongReference) {  
      8.       value = ((StrongReference) ref).get();  
      9.     } else if (ref instanceof SoftReference) {  
      10.       value = ((SoftReference) ref).get();  
      11.     } else if (ref instanceof WeakReference) {  
      12.       value = ((WeakReference) ref).get();  
      13.     }  
      14.   }  
      15.   return value;  
      16. }  

         3 唯一標識的生成

            在iBATIS中,用CacheKey來標識一個緩存對象,而CacheKey通常是作為Map中的key存在,所以CacheKey的hashCode的計算方法異常重要。影響hashCode的值有很多方面的因素,對每一個影響hashCode的元素,都需要調用CacheKey的update方法來重新計算hashCode值。下面我們就來看一下CacheKey的創建以及計算的相關過程。

            首先CacheKey是在BaseDataExchange類的getCacheKey方法中被創建的。

      1. public CacheKey getCacheKey(StatementScope statementScope, ParameterMap parameterMap, Object parameterObject) {  
      2.   CacheKey key = new CacheKey();  
      3.   //取得parameterObject中的數據,這個parameterObject就是客戶端傳遞過來的參數對象  
      4.   Object[] data = getData(statementScope, parameterMap, parameterObject);  
      5.   //根據parameterObject中的數據去重計算hashCode  
      6.   for (int i = 0; i < data.length; i++) {  
      7.     if (data[i] != null) {  
      8.       key.update(data[i]);  
      9.     }  
      10.   }  
      11.   return key;  
      12. }  

            這個方法被MappedStatement中的getCacheKey調用

      1. public CacheKey getCacheKey(StatementScope statementScope, Object parameterObject) {  
      2.   Sql sql = statementScope.getSql();  
      3.   ParameterMap pmap = sql.getParameterMap(statementScope, parameterObject);  
      4.   CacheKey cacheKey = pmap.getCacheKey(statementScope, parameterObject);  
      5.   //statement id對hashCode有影響  
      6.   cacheKey.update(id);  
      7.   cacheKey.update(baseCacheKey);  
      8.   //sql語句對hashCode有影響  
      9.   cacheKey.update(sql.getSql(statementScope, parameterObject)); //Fixes bug 953001  
      10.   return cacheKey;  
      11. }  

           真正需要CacheKey對象的地方是在CacheStatement類中

      1. public CacheKey getCacheKey(StatementScope statementScope, Object parameterObject) {  
      2.   CacheKey key = statement.getCacheKey(statementScope, parameterObject);  
      3.   //如果不可讀并且不被序列化,那么當前的SessionScope也對hashCode有影響  
      4.    //而真正起作用的是SessionScope的id屬性  
      5.    //也就是說這個緩存與調用線程的會話有關,當前線程所存儲的數據不能被其他線程使用  
      6.   if (!cacheModel.isReadOnly() && !cacheModel.isSerialize()) {  
      7.     key.update(statementScope.getSession());  
      8.   }  
      9.   return key;  
      10. }  

          經過上述一系列的getCacheKey調用,將對CacheKey有影響的因素施加給了hashCode。其中對CacheKey的hashCode起影響作用的因素主要有:baseCacheKey,sql語句,參數值,statement id。可能產生影響的因素是session id。

          現在我們知道了決定CacheKey的相關因素,也就知道了iBATIS是如何唯一的確定一個緩存對象。

          經過以上的代碼分析,可以掌握iBatis如何生成CacheKey對象和計算其hashCode值,以及存儲和檢索數據對象。這些正是iBATIS緩存的基礎,掌握了這些實現原理,有助于我們更高效的使用iBATIS緩存功能,或者是開發自己的緩存系統。

      posted @ 2011-03-14 19:44  abstractwind  閱讀(2035)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产精品一线天粉嫩av| 亚洲精品亚洲人成在线| 亚洲一区二区精品动漫| 孕妇怀孕高潮潮喷视频孕妇 | 国产高清自产拍av在线| 少妇被粗大的猛进出69影院| 男人av无码天堂| 国产a在视频线精品视频下载| 无码人妻精品一区二区三区蜜桃| 欧美人与动牲猛交A欧美精品| 国产精品中文字幕自拍| 国产免费午夜福利蜜芽无码| 国产不卡一区在线视频| 日韩狼人精品在线观看| 亚洲精品国产av成人网| 亚洲av日韩av永久无码电影| 加勒比中文字幕无码一区| 久久婷婷成人综合色综合| 日本不卡的一区二区三区| 精品久久久久久久中文字幕| 国产真人无遮挡免费视频| 国产一区日韩二区三区| 蒲城县| 在线综合亚洲欧洲综合网站| 中美日韩在线一区黄色大片| 亚洲中文字幕人妻系列| 久久国内精品自在自线91| 40岁大乳的熟妇在线观看| 精品人妻中文字幕av| 日本中文一二区有码在线| 国产在线一区二区不卡| 桂阳县| 综合久青草视频在线观看| 麻豆久久久9性大片| 国产人成777在线视频直播| 亚洲 一区二区 在线| 亚洲av色香蕉一二三区| 少妇激情a∨一区二区三区| 四虎成人精品无码| 国产精品自在线拍国产手青青机版| 亚洲国产精品综合久久2007|