yxhxj2006

          常用鏈接

          統計

          最新評論

          ibatis 開發指南 3

          接 ibatis 開發指南 2 

          Cache 
          在特定硬件基礎上(同時假設系統不存在設計上的缺漏和糟糕低效的 SQL 語句) 
          Cache往往是提升系統性能的最關鍵因素)。 
          相對 Hibernate 等封裝較為嚴密的 ORM 實現而言(因為對數據對象的操作實現 
          了較為嚴密的封裝,可以保證其作用范圍內的緩存同步,而 ibatis 提供的是半封閉 
          的封裝實現,因此對緩存的操作難以做到完全的自動化同步)。 
          ibatis 的緩存機制使用必須特別謹慎。特別是 flushOnExecute 的設定(見 
          “ibatis配置”一節中的相關內容),需要考慮到所有可能引起實際數據與緩存數據 
          不符的操作。如本模塊中其他Statement對數據的更新,其他模塊對數據的更新,甚 
          至第三方系統對數據的更新。否則,臟數據的出現將為系統的正常運行造成極大隱患。 
          如果不能完全確定數據更新操作的波及范圍,建議避免 Cache的盲目使用。 
          結合cacheModel來看: 
          <cacheModel >
          id="product-cache" 
          type ="LRU" 
          readOnly="true" 
          serialize="false"> 
          </cacheModel> 

          可以看到,Cache有如下幾個比較重要的屬性: 
          ÿ readOnly 
          ÿ serialize 
          ÿ type 

          readOnly 
          readOnly值的是緩存中的數據對象是否只讀。 這里的只讀并不是意味著數據對象一 
          旦放入緩存中就無法再對數據進行修改。而是當數據對象發生變化的時候,如數據對 
          象的某個屬性發生了變化,則此數據對象就將被從緩存中廢除,下次需要重新從數據 
          庫讀取數據,構造新的數據對象。 
          而 readOnly="false"則意味著緩存中的數據對象可更新,如 user 對象的 name 
          屬性發生改變。 
          只讀Cache能提供更高的讀取性能,但一旦數據發生改變,則效率降低。系統設計 
          時需根據系統的實際情況(數據發生更新的概率有多大)來決定 Cache的讀寫策略。 

          serialize 
          如果需要全局的數據緩存,CacheModel的 serialize屬性必須被設為true。否則數據 
          緩存只對當前 Session(可簡單理解為當前線程)有效,局部緩存對系統的整體性能提 
          升有限。 
          在 serialize="true"的情況下,如果有多個 Session同時從 Cache 中讀取某個 
          數據對象,Cache 將為每個 Session返回一個對象的復本,也就是說,每個 Session將 
          得到包含相同信息的不同對象實例。因而 Session 可以對其從 Cache 獲得的數據進行 
          存取而無需擔心多線程并發情況下的同步沖突。 


          Cache Type: 
          與hibernate類似,ibatis通過緩沖接口的插件式實現,提供了多種 Cache的實現機 
          制可供選擇: 
          1. MEMORY 
          2. LRU 
          3. FIFO 
          4. OSCACHE 

          MEMORY類型Cache與 WeakReference 
          MEMORY 類型的 Cache 實現,實際上是通過 Java 對象引用進行。ibatis 中,其實現類 
          為com.ibatis.db.sqlmap.cache.memory.MemoryCacheController, MemoryCacheController 內部, 
          使用一個HashMap來保存當前需要緩存的數據對象的引用。 

          這里需要注意的是Java2中的三種對象引用關系: 
          a SoftReference 
          b WeakReference 
          c PhantomReference 
          傳統的Java 對象引用,如: 
          public void doSomeThing(){ 
          User user = new User() 
          …… 

          當doSomeThing方法結束時,user 對象的引用丟失,其所占的內存空間將由JVM在下 
          次垃圾回收時收回。如果我們將user 對象的引用保存在一個全局的 HashMap中,如: 
          Map map = new HashMap(); 

          public void doSomeThing(){ 
          User user = new User(); 
          map.put("user",user); 

          此時,user 對象由于在 map 中保存了引用,只要這個引用存在,那么 JVM 永遠也不會 
          收回user 對象所占用的內存。 
          這樣的內存管理機制相信諸位都已經耳熟能詳,在絕大多數情況下,這幾乎是一種完美 的解決方案。但在某些情況下,卻有些不便。如對于這里的 Cache 而言,當 user 對象使用 
          之后,我們希望保留其引用以供下次需要的時候可以重復使用,但又不希望這個引用長期保 
          存,如果每個對象的引用都長期保存下去的話,那隨著時間推移,有限的內存空間將立即被 
          這些數據所消耗殆盡。最好的方式,莫過于有一種引用方式,可以在對象沒有被垃圾回收器 
          回收之前, 依然能夠訪問此對象,當垃圾回收器啟動時, 如果此對象沒有被其他對象所使用, 
          則按照常規對其進行回收。 

          SoftReference、WeakReference、PhantomReference為上面的思路提供了有力支持。 

          這三種類型的引用都屬于“非持續性引用”,也就是說,這種引用關系并非持續存在, 
          它們所代表的引用的生命周期與JVM 的運行密切相關,而非與傳統意義上的引用一樣依賴 
          于編碼階段的預先規劃。 
          先看一個SoftReference的例子: 
          SoftReference ref; 

          public void doSomeThing(){ 
          User user = new User(); 
          ref = new SoftReference(user); 


          public void doAnotherThing(){ 
          User user = (User)ref.get();//通過SoftReference獲得對象引用 
          System.out.println(user.getName()); 



          假設我們先執行了 doSomeThing 方法,產生了一個 User 對象,并為其創建了一個 
          SoftReference引用。 
          之后的某個時刻,我們調用了doAnotherThing方法,并通過 SoftReference獲取 User 對 
          象的引用。 
          此時我們是否還能取得user 對象的引用?這要看JVM的運行情況。對于 SoftReference 
          而言,只有當目前內存不足的情況下,JVM 在垃圾回收時才會收回其包含的引用(JVM 并 
          不是只有當內存不足時才啟動垃圾回收機制,何時進行垃圾回收取決于各版本 JVM 的垃圾 
          回收策略。如某這垃圾回收策略為:當系統目前較為空閑,且無效對象達到一定比率時啟動 
          垃圾回收機制,此時的空余內存倒可能還比較充裕)。這里可能出現兩種情況,即: 

          ÿ JVM 目前還未出現過因內存不足所引起的垃圾回收,user 對象的引用可以通過 
          SoftReference從JVM Heap中收回。 
          ÿ JVM已經因為內存不足啟動了垃圾回收機制,SoftReference所包含的 user 對象的 
          引用被JVM所廢棄。此時 ref.get方法將返回一個空引用(null),對于上面 
          的代碼而言,也就意味著這里可能拋出一個 NullPointerException。 

          WeakReference比SoftReference在引用的維持性上來看更加微弱。 無需等到內存不足的 
          情況, 只要JVM啟動了垃圾回收機制, 那么WeakReference所對應的對象就將被JVM回收。 
          也就是說,相對SoftReference而言,WeakReference 被 JVM回收的概率更大。 

          PhantomReference 比 WeakReference 的引用維持性更弱。與 WeakReference 和 
          SoftReference不同,PhantomReference所引用的對象幾乎無法被回收重用。它指向的對象實 
          際上已經被JVM銷毀(finalize方法已經被執行),只是暫時還沒被垃圾回收器收回而已。 
          PhantomReference主要用于輔助對象的銷毀過程,在實際應用層研發中,幾乎不會涉及。 

          MEMORY類型的Cache正是借助SoftReference、 WeakReference以及通常意義上的Java 
          Reference實現了對象的緩存管理。 
          下面是一個典型的MEMORY類型 Cache配置: 
          <cacheModel id="user_cache" type="MEMORY"> 
          <flushInterval hours="24"/> 
          <flushOnExecute statement="updateUser"/> 
          <property name="reference-type" value="WEAK" /> 
          </cacheModel> 
          其中 flushInterval 指定了多長時間清除緩存,上例中指定每 24 小時強行清空緩存 
          區的所有內容。 
          reference-type屬性可以有以下幾種配置: 
          1. STRONG 
          即基于傳統的Java對象引用機制,除非對Cache顯式清空(如到了flushInterval 
          設定的時間;執行了flushOnExecute所指定的方法;或代碼中對Cache執行了清除 
          操作等),否則引用將被持續保留。 
          此類型的設定適用于緩存常用的數據對象,或者當前系統內存非常充裕的情況。 
          2. SOFT 
          基于 SoftReference 的緩存實現,只有 JVM 內存不足的時候,才會對緩沖池中的數 
          據對象進行回收。 
          此類型的設定適用于系統內存較為充裕,且系統并發量比較穩定的情況。 
          3. WEAK 
          基于 WeakReference 的緩存實現,當 JVM 垃圾回收時,緩存中的數據對象將被 JVM 
          收回。 
          一般情況下,可以采用WEAK的MEMORY型Cache配置。 

          LRU型 Cache 
          當 Cache達到預先設定的最大容量時,ibatis會按照“最少使用”原則將使用頻率最少 
          的對象從緩沖中清除。 
          <cacheModel id="userCache" type="LRU"> 
          <flushInterval hours="24"/> 
          <flushOnExecute statement="updateUser"/> 
          <property name="size" value="1000" /> 
          </cacheModel> 
          可配置的參數有: 
          u flushInterval 
          指定了多長時間清除緩存, 上例中指定每24小時強行清空緩存區的所有內容。 
          u size Cache的最大容量。 

          FIFO型 Cache 
          先進先出型緩存,最先放入Cache中的數據將被最先廢除。可配置參數與 LRU型相同: 
          <cacheModel id="userCache" type="FIFO"> 
          <flushInterval hours="24"/> 
          <flushOnExecute statement="updateUser"/> 
          <property name="size" value="1000" /> 
          </cacheModel> 

          OSCache 

          與上面幾種類型的Cache不同,OSCache來自第三方組織 Opensymphony。可以通過以 
          下網址獲得OSCache的最新版本(http://www.opensymphony.com/oscache/)。 

          在生產部署時,建議采用 OSCache,OSCache 是得到了廣泛使用的開源 Cache 實現 
          (Hibernate 中也提供了對 OSCache 的支持),它基于更加可靠高效的設計,更重要的是, 
          最新版本的 OSCache 已經支持 Cache 集群。如果系統需要部署在集群中,或者需要部署在 
          多機負載均衡模式的環境中以獲得性能上的優勢,那么OSCache在這里則是不二之選。 

          Ibatis中對于OSCache的配置相當簡單: 
          <cacheModel id="userCache" type="OSCACHE"> 
          <flushInterval hours="24"/> 
          <flushOnExecute statement="updateUser"/> 
          <property name="size" value="1000" /> 
          </cacheModel> 

          之所以配置簡單,原因在于,OSCache擁有自己的配置文件(oscache.properties)J。 
          下面是一個典型的OSCache配置文件: 
          #是否使用內存作為緩存空間 
          cache.memory=true 

          #緩存管理事件監聽器,通過這個監聽器可以獲知當前Cache的運行情況 
          cache.event.listeners=com.opensymphony.oscache.plugins.clustersupport.JMSBroa 
          dcastingListener 

          #如果使用磁盤緩存(cache.memory=false),則需要指定磁盤存儲接口實現 
          #cache.persistence.class=com.opensymphony.oscache.plugins.diskpersistence.Disk 
          PersistenceListener 

          # 磁盤緩存所使用的文件存儲路徑 
          # cache.path=c:\\myapp\\cache 

          # 緩存調度算法,可選的有LRU,FIFO和無限緩存(UnlimitedCache) # cache.algorithm=com.opensymphony.oscache.base.algorithm.FIFOCache 
          # cache.algorithm=com.opensymphony.oscache.base.algorithm.UnlimitedCache 
          cache.algorithm=com.opensymphony.oscache.base.algorithm.LRUCache 

          #內存緩存的最大容量 
          cache.capacity=1000 

          # 是否限制磁盤緩存的容量 
          # cache.unlimited.disk=false 

          # 基于JMS的集群緩存同步配置 
          #cache.cluster.jms.topic.factory=java:comp/env/jms/TopicConnectionFactory 
          #cache.cluster.jms.topic.name=java:comp/env/jms/OSCacheTopic 
          #cache.cluster.jms.node.name=node1 

          # 基于JAVAGROUP的集群緩存同步配置 
          #cache.cluster.properties=UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ 
          ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):PING(timeout 
          =2000;num_initial_members=3):MERGE2(min_interval=5000;max_interval=10000 
          ):FD_SOCK:VERIFY_SUSPECT(timeout=1500):pbcast.NAKACK(gc_lag=50;retransm 
          it_timeout=300,600,1200,2400,4800):pbcast.STABLE(desired_avg_gossip=20000): 
          UNICAST(timeout=5000):FRAG(frag_size=8096;down_thread=false;up_thread=fal 
          se):pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_loc 
          al_addr=true) 
          #cache.cluster.multicast.ip=231.12.21.132 

          配置好之后,將此文件放在 CLASSPATH 中,OSCache 在初始化時會自動找到此 
          文件并根據其中的配置創建緩存實例。 
          ibatis in Spring 
          這里我們重點探討Spring框架下的ibatis應用,特別是在容器事務管理模式下的ibatis 
          應用開發。 

          關于Spring Framework,請參見筆者另一篇文檔: 
          《Spring 開發指南》http://www.xiaxin.net/Spring_Dev_Guide.rar 

          針對ibatis,Spring配置文件如下: 

          Ibatis-Context.xml: 
          <?xml version="1.0" encoding="UTF-8"?> 
          <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" >
          "http://www.springframework.org/dtd/spring-beans.dtd"> 

          <beans> 

          <bean id="dataSource" >
          class="org.apache.commons.dbcp.BasicDataSource" 
          destroy-method="close"> 
          <property name="driverClassName"> 
          <value>net.sourceforge.jtds.jdbc.Driver</value> 
          </property> 
          <property name="url"> 
          <value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value> 
          </property> 
          <property name="username"> 
          <value>test</value> 
          </property> 
          <property name="password"> 
          <value>changeit</value> 
          </property> 
          </bean> 

          <bean id="sqlMapClient" >
          class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> 
          <property name="configLocation"> 
          <value>SqlMapConfig.xml</value> 
          </property> 
          </bean> 

          <bean id="transactionManager" >
          class="org.springframework.jdbc.datasource.DataSourceTransactio 
          nManager"> <property name="dataSource"> 
          <ref local="dataSource"/> 
          </property> 
          </bean> 

          <bean id="userDAO" class="net.xiaxin.dao.UserDAO"> 
          <property name="dataSource"> 
          <ref local="dataSource" /> 
          </property> 
          <property name="sqlMapClient"> 
          <ref local="sqlMapClient" /> 
          </property> 
          </bean> 

          <bean id="userDAOProxy" >
          class="org.springframework.transaction.interceptor.TransactionPro 
          xyFactoryBean"> 

          <property name="transactionManager"> 
          <ref bean="transactionManager" /> 
          </property> 

          <property name="target"> 
          <ref local="userDAO" /> 
          </property> 

          <property name="transactionAttributes"> 
          <props> 
          <prop key="insert*">PROPAGATION_REQUIRED</prop> 
          <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> 
          </props> 
          </property> 
          </bean> 
          </beans> 

          可以看到: 
          1. sqlMapClient節點 
          sqlMapClient節點實際上配置了一個sqlMapClient的創建工廠類。 
          configLocation屬性配置了ibatis映射文件的名稱。 

          2. transactionManager節點 
          transactionManager采用了Spring中的DataSourceTransactionManager。 

          3. userDAO節點 對應的,UserDAO需要配置兩個屬性,sqlMapClient和DataSource, 
          sqlMapClient將從指定的DataSource中獲取數據庫連接。 

          本例中Ibatis映射文件非常簡單: 

          sqlMapConfig.xml: 
          <sqlMapConfig> 
          <sqlMap resource="net/xiaxin/dao/entity/user.xml"/> 
          </sqlMapConfig> 

          net/xiaxin/dao/entity/user .xml 
          <sqlMap namespace="User"> 
          <typeAlias alias="user" type="net.xiaxin.dao.entity.User" /> 

          <insert id="insertUser" parameterClass="user"> 
          INSERT INTO users ( username, password) VALUES ( #username#, 
          #password# ) 
          </insert> 

          </sqlMap> 

          UserDAO.java: 
          public class UserDAO extends SqlMapClientDaoSupport implements 
          IUserDAO { 

          public void insertUser(User user) { 
          getSqlMapClientTemplate().update("insertUser", user); 


          SqlMapClientDaoSupport(如果使用ibatis 1.x版本,對應支持類是 
          SqlMapDaoSupport)是Spring中面向ibatis的輔助類,它負責調度DataSource、 
          SqlMapClientTemplate(對應ibatis 1.x版本是SqlMapTemplate)完成ibatis操作, 
          而DAO則通過對此類進行擴展獲得上述功能。上面配置文件中針對UserDAO的屬性設 
          置部分,其中的屬性也是繼承自于這個基類。 

          SqlMapClientTemplate對傳統SqlMapClient調用模式進行了封裝,簡化了上層訪問 
          代碼。 

          User .java: 
          public class User { 

          public Integer id; 

          public String username; public String password; 

          public Integer getId() { 
          return id; 


          public void setId(Integer id) { 
          this.id = id; 

          public String getPassword() { 
          return password; 


          public void setPassword(String password) { 
          this.password = password; 


          public String getUsername() { 
          return username; 


          public void setUsername(String username) { 
          this.username = username; 



          測試代碼: 
          InputStream is = new FileInputStream("Ibatis-Context.xml"); 
          XmlBeanFactory factory = new XmlBeanFactory(is); 
          IUserDAO userdao = (IUserDAO)factory.getBean("userDAOProxy"); 

          User user = new User(); 
          user.setUsername("Sofia"); 
          user.setPassword("mypass"); 

          userdao.insertUser(user); 

          對比前面 ibatis 程序代碼,我們可以發現 UserDAO.java 變得異常簡潔,這也正是 
          Spring Framework為我們帶來的巨大幫助。 

          Spring以及其他IOC 框架對傳統的應用框架進行了顛覆性的革新, 也許這樣的評價有 
          點過于煽情,但是這確是筆者第一次跑通 Spring HelloWorld 時的切身感受。有興趣的 
          讀者可以研究一下Spring framework,enjoy it! 

          posted on 2012-09-20 00:56 奮斗成就男人 閱讀(579) 評論(0)  編輯  收藏 所屬分類: J2EE

          主站蜘蛛池模板: 耿马| 清镇市| 英德市| 上高县| 江油市| 郓城县| 温州市| 社会| 甘肃省| 珠海市| 黄龙县| 岳阳县| 砚山县| 辽源市| 合作市| 罗城| 铜陵市| 晋江市| 旺苍县| 乌什县| 金山区| 辰溪县| 武穴市| 沂源县| 菏泽市| 横山县| 海口市| 万盛区| 炉霍县| 宝鸡市| 乌兰县| 白玉县| 砀山县| 栾城县| 华容县| 孝义市| 新野县| 乐山市| 三江| 松阳县| 邻水|