yxhxj2006

          常用鏈接

          統(tǒng)計

          最新評論

          ibatis 開發(fā)指南 3

          接 ibatis 開發(fā)指南 2 

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

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

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

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


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

          MEMORY類型Cache與 WeakReference 
          MEMORY 類型的 Cache 實現(xiàn),實際上是通過 Java 對象引用進行。ibatis 中,其實現(xiàn)類 
          為com.ibatis.db.sqlmap.cache.memory.MemoryCacheController, MemoryCacheController 內(nèi)部, 
          使用一個HashMap來保存當(dāng)前需要緩存的數(shù)據(jù)對象的引用。 

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

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

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

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

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

          這三種類型的引用都屬于“非持續(xù)性引用”,也就是說,這種引用關(guān)系并非持續(xù)存在, 
          它們所代表的引用的生命周期與JVM 的運行密切相關(guān),而非與傳統(tǒng)意義上的引用一樣依賴 
          于編碼階段的預(yù)先規(guī)劃。 
          先看一個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()); 



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

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

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

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

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

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

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

          OSCache 

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

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

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

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

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

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

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

          # 緩存調(diào)度算法,可選的有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 

          #內(nèi)存緩存的最大容量 
          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 在初始化時會自動找到此 
          文件并根據(jù)其中的配置創(chuàng)建緩存實例。 
          ibatis in Spring 
          這里我們重點探討Spring框架下的ibatis應(yīng)用,特別是在容器事務(wù)管理模式下的ibatis 
          應(yīng)用開發(fā)。 

          關(guān)于Spring Framework,請參見筆者另一篇文檔: 
          《Spring 開發(fā)指南》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節(jié)點 
          sqlMapClient節(jié)點實際上配置了一個sqlMapClient的創(chuàng)建工廠類。 
          configLocation屬性配置了ibatis映射文件的名稱。 

          2. transactionManager節(jié)點 
          transactionManager采用了Spring中的DataSourceTransactionManager。 

          3. userDAO節(jié)點 對應(yīng)的,UserDAO需要配置兩個屬性,sqlMapClient和DataSource, 
          sqlMapClient將從指定的DataSource中獲取數(shù)據(jù)庫連接。 

          本例中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版本,對應(yīng)支持類是 
          SqlMapDaoSupport)是Spring中面向ibatis的輔助類,它負責(zé)調(diào)度DataSource、 
          SqlMapClientTemplate(對應(yīng)ibatis 1.x版本是SqlMapTemplate)完成ibatis操作, 
          而DAO則通過對此類進行擴展獲得上述功能。上面配置文件中針對UserDAO的屬性設(shè) 
          置部分,其中的屬性也是繼承自于這個基類。 

          SqlMapClientTemplate對傳統(tǒng)SqlMapClient調(diào)用模式進行了封裝,簡化了上層訪問 
          代碼。 

          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 程序代碼,我們可以發(fā)現(xiàn) UserDAO.java 變得異常簡潔,這也正是 
          Spring Framework為我們帶來的巨大幫助。 

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

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

          主站蜘蛛池模板: 南通市| 冀州市| 衡阳市| 昔阳县| 青河县| 涟源市| 双鸭山市| 日喀则市| 沭阳县| 哈尔滨市| 西林县| 玉田县| 鄂伦春自治旗| 疏附县| 肥城市| 金沙县| 贺兰县| 吉隆县| 盐津县| 丹凤县| 沙雅县| 根河市| 辛集市| 五峰| 天水市| 浦县| 南充市| 郓城县| 高青县| 礼泉县| 河源市| 修水县| 大田县| 西丰县| 尼玛县| 石楼县| 吉安市| 麻江县| 湾仔区| 土默特右旗| 芦山县|