西沙璞玉
          愛不容易
          posts - 0,comments - 4,trackbacks - 0
          引子

          今天下班后,以前同事小胖問我Spring  Service類中的注解@Transactional readOnly=true的作用。做為他眼中的高人,我自然要裝下A-C。居然想都沒有想就說是注解事務(wù)控制,然后給他扯了一通數(shù)據(jù)庫的隔離級別,什么read uncommit之類的,說readOnly是隔離級別最低的,在spring查詢方法里用,性能最高。
          ps:之前的項(xiàng)目多數(shù)基于xml,親自用annotation的機(jī)會很少,都是小弟們在實(shí)戰(zhàn)。

          示例:
          Java代碼  收藏代碼
          1. @Component("channelService"
          2. @Transactional(readOnly = true
          3. public class ChannelServiceImpl implements IChannelService { 
          4.     @Resource(name = "productService"
          5.     private IProductService productService; 
          6.  
          7.     /**
          8.      * 根據(jù)頻道名字查詢頻道。沒有就返回NULL。
          9.      *
          10.      * @param name 頻道名稱不能為空。
          11.      * @return (假設(shè)頻道名稱是加了唯一約束的,否則可能結(jié)果不止一條導(dǎo)致異常)
          12.      */ 
          13.     @MethodCache(expire = 3600
          14.     @Transactional(readOnly = true
          15.     public ChannelVO getChannelByName(String name) { 
          16.         if (name == null || "".equals(name.trim())) { 
          17.             throw new IllegalArgumentException("name=" + name); 
          18.         } 
          19.         ShopChannels channel = (ShopChannels) channelDao.createCriteria() 
          20.                 .add(Restrictions.eq("name", name)) 
          21.                 .uniqueResult(); 
          22.         if (channel == null) { 
          23.             return new ChannelVO(); 
          24.         } 
          25.         ChannelVO vo = new ChannelVO(); 
          26.         DozerMapper.getInstance().map(channel, vo); 
          27.         //增加頻道對應(yīng)商品分類id 只取第一個分類 
          28.         Set<ProductClass> listCates = channel.getProductClasses(); 
          29.         if (listCates != null && !listCates.isEmpty()) { 
          30.             vo.setProductClass("" + listCates.iterator().next().getSid()); 
          31.         } 
          32.         List<Integer> list = new ArrayList<Integer>(); 
          33.         Iterator<ProductClass> iterator = listCates.iterator(); 
          34.         while (iterator.hasNext()) { 
          35.             ProductClass productClass = iterator.next(); 
          36.             list.add(productClass.getSid()); 
          37.         } 
          38.         vo.setAllProductClass(list); 
          39.         return vo; 


          數(shù)據(jù)庫隔離相關(guān)內(nèi)容

          在一個應(yīng)用中,依據(jù)事務(wù)的隔離級別將會有三種情況發(fā)生。
            ◆臟讀(dirty read):當(dāng)一個事務(wù)讀取另一個事務(wù)尚未提交的修改時,產(chǎn)生臟讀。
            ◆ 不可重復(fù)讀(non-repeatable read):同一查詢在同一事務(wù)中多次進(jìn)行,由于其他提交事務(wù)所做的修改或刪除,每次返回不同的結(jié)果集,此時發(fā)生非重復(fù)讀。:
            ◆ 幻像讀(phantom read):同一查詢在同一事務(wù)中多次進(jìn)行,由于其他提交事務(wù)所做的插入操作,每次返回不同的結(jié)果集,此時發(fā)生幻像讀。

          1.Read Committed:
          假設(shè)A事務(wù)對正在讀取數(shù)據(jù)Data放置了共享鎖,那么Data不能被其它事務(wù)改寫,所以當(dāng)B事務(wù)對Data進(jìn)行讀取時總和A讀取的Data數(shù)據(jù)是一致的,所以避免了臟讀。由于在A沒有提交之前可以對Data進(jìn)行改寫,那么B讀取到的某個值可能會在其讀取后被A更改從而導(dǎo)致了該值不能被重復(fù)取得;或者當(dāng)B再次用相同的where字句時得到了和前一次不一樣數(shù)據(jù)的結(jié)果集,也就是幻像數(shù)據(jù)。

          2.Read Uncommitted:
          假設(shè)A事務(wù)即不發(fā)布共享鎖,也不接受獨(dú)占鎖,那么并發(fā)的B或者其它事務(wù)可以改寫A事務(wù)讀取的數(shù)據(jù),那么并發(fā)的C事務(wù)讀取到的數(shù)據(jù)的狀態(tài)和A的或者B的數(shù)據(jù)都可能不一致,那么。臟讀、不可重復(fù)讀、幻象數(shù)據(jù)都可能存在。

          3.Repeatable Read:
          (注意MSDN原文中的第一句話:在查詢中使用的所有數(shù)據(jù)上放置鎖,所以不存在臟讀的情況)。
          假設(shè)A事務(wù)對讀取的所有數(shù)據(jù)Data放置了鎖,以阻止其它事務(wù)對Data的更改,在A沒有提交之前,新的并發(fā)事務(wù)讀取到的數(shù)據(jù)如果存在于Data中,那么該數(shù)據(jù)的狀態(tài)和A事務(wù)中的數(shù)據(jù)是一致的,從而避免了不可重復(fù)的讀取。但在A事務(wù)沒有結(jié)束之前,B事務(wù)可以插入新記錄到Data所在的表中,那么其它事務(wù)再次用相同的where字句查詢時,得到的結(jié)果數(shù)可能上一次的不一致,也就是幻像數(shù)據(jù)。

          4.Serializable:
          在數(shù)據(jù)表上放置了排他鎖,以防止在事務(wù)完成之前由其他用戶更新行或向數(shù)據(jù)集中插入行,這是最嚴(yán)格的鎖。它防止了臟讀、不可重復(fù)讀取和幻象數(shù)據(jù)。

          以下是對照表:




          一般的應(yīng)用作隔離級別時,往往采用(2),(3)兩種,(1),(4)兩種前者輕后者重,但是Hibernate為了提高performance和scalability,在數(shù)據(jù)庫一層中采用的是(2)的隔離級別,然后在程序中進(jìn)行控制,從而實(shí)現(xiàn)了(3)的隔離級別,因此提高了企業(yè)應(yīng)用的事務(wù)處理效率。當(dāng)然Hibernate對于數(shù)據(jù)庫一層的隔離級別也可以顯示指定。Hibernate在程序中的控制方法有:version number, timestamp,對于遺留database也有optimistic-lock,而version number有時不能解決特殊的事務(wù)并發(fā)引起來的(3)問題,那么就需要針對特殊情況進(jìn)行細(xì)粒度的事務(wù)控制,可以看一下LOCKMODE。

          回家反思緩存策略

          回家一想,不對,應(yīng)該不完全是隔離級別的東西,自已可能肯定搞錯了,于是趕緊翻看hibernate3.3 reference.果然沒說對。應(yīng)該是二級緩存的策略問題。但不知為什么reference中沒有講到query cache annotation的東西,只是一頁帶過。提高性能中二級緩存策略倒是講了不少。
          備忘:

          Chapter 19. Improving performance
          19.2. The Second Level Cache

          19.2.1. Cache mappings
          The <cache> element of a class or collection mapping has the following form:
          Java代碼  收藏代碼
          1. <cache  
          2.     usage="transactional|read-write|nonstrict-read-write|read-only"   
          3.     region="RegionName"                                               
          4.     include="all|non-lazy"                                            
          5. /> 
          usage (required) specifies the caching strategy: transactional, read-write, nonstrict-
          read-write or read-only
          region (optional: defaults to the class or collection role name): specifies the name of the
          second level cache region
          include (optional: defaults to all) non-lazy: specifies that properties of the entity mapped
          with lazy="true" cannot be cached when attribute-level lazy fetching is enabled
          Alternatively, you  can  specify  <class-cache> and  <collection-cache>  elements  in
          hibernate.cfg.xml.
          The usage attribute specifies a cache concurrency strategy.

          直接簡要的看各種策略說明:

          Strategy: read only
          If your application needs to read, but not modify, instances of a persistent class, a read-only
          cache can be used. This is the simplest and optimal performing strategy. It is even safe for use
          in a cluster.
          如果應(yīng)用只需要查詢,不需要修改,那么read-only緩存將使用,這是最簡單、最理想的性能策略,它在集群環(huán)境下也是安全的。

          Strategy: read/write
          If  the  application  needs  to  update  data, a  read-write  cache  might  be  appropriate.This  cache  strategy  should  never  be  used  if  serializable  transaction  isolation  level  is required. 
          如果應(yīng)用需要修改,read-write cache是最合適的。這個cache策略永遠(yuǎn)不會使用,如果數(shù)據(jù)庫事務(wù)隔離級別是可序列化serializable的。這里看和隔離級別又有點(diǎn)關(guān)系。

          Strategy: nonstrict  read/write
          If the application only occasionally needs to update data (i.e. if it is extremely unlikely that two
          transactions would try to update the same item simultaneously), and strict transaction isolation
          is not required, a nonstrict-read-write cache might be appropriate. If the cache is used in a
          JTA environment, you must specify hibernate.transaction.manager_lookup_class. In other
          environments, you should ensure that the transaction is completed when Session.close() or
          Session.disconnect() is called.
          如果應(yīng)用僅僅偶爾的修改數(shù)據(jù),并不需要嚴(yán)格的數(shù)據(jù)庫隔離級別。Nonstrict-read-write 緩存是最合適的。

          Strategy: transactional
          The transactional cache strategy provides support for fully  transactional cache providers such
          as JBoss TreeCache. Such a cache can only be used in a JTA environment and you must specify
          hibernate.transaction.manager_lookup_class.
          The transactional cache strategy提供完全的事務(wù)緩存機(jī)制,例如JBoss TreeCache.這樣的緩存只能用在JTA環(huán)境中,你也必需指定相關(guān)類。

          Important
          None of the cache providers support all of the cache concurrency strategies.
          The following table shows which providers are compatible with which concurrency strategies.




          回歸正題@Transactional

          再想想,還是不對,hibernate中并沒有提到最開始annotation的東西,于是繼續(xù)糾結(jié)Spring3.0 Reference Documentation。

          Using @Transactional
          In addition to the XML-based declarative approach to transaction configuration, you can use an
          annotation-based approach. Declaring transaction semantics directly in the Java source code puts the declarations much closer to the affected code. There is not much danger of undue coupling, because code that is meant to be used transactionally is almost always deployed that way anyway.
          annotation事務(wù)控制,代替xml的。其它廢話少翻。
          You can place the @Transactional annotation before an interface definition, a method on an Interface, a class definition, or a public method on a class. However, the mere presence of the
          @Transactional annotation is not enough to activate the transactional behavior. The
          @Transactional annotation is simply metadata that can be consumed by some runtime infrastructure that is @Transactional-aware and that can use the metadata to configure the appropriate beans with transactional behavior. In the preceding example, the <tx:annotation-driven/> element switches
          onthetransactionalbehavior.

          Java代碼  收藏代碼
          1. //文檔例子: 
          2. @Transactional(readOnly = true
          3. public class DefaultFooService implements FooService { 
          4. public Foo getFoo(String fooName) { 
          5. // do something 
          6. // these settings have precedence for this method 
          7. @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) 
          8. public void updateFoo(Foo foo) { 
          9. // do something 


          @Transactional  settings
          The @Transactional annotation is metadata that specifies that an interface, class, or method must have transactional semantics; for example, “start a brand new read-only transaction when this method is invoked。
          @Transactional 注解是規(guī)定接口,類或者方法必需應(yīng)用事務(wù)的元數(shù)據(jù)語法。

          看看spring默認(rèn)的設(shè)置:
          Java代碼  收藏代碼
          1. //默認(rèn)傳播機(jī)制:PROPAGATION_REQUIRED 
          2. * Propagation setting is PROPAGATION_REQUIRED. 
          3. //默認(rèn)隔離級別:ISOLATION_DEFAULT 
          4. * Isolation level is ISOLATION_DEFAULT. 
          5. //默認(rèn)事務(wù)是read/write.到此知道查詢配readOnly的作用。 
          6. * Transaction is read/write. 
          7. //事務(wù)默認(rèn)超時時間取決于事務(wù)系統(tǒng),也有可能沒有,如果事務(wù)系統(tǒng)不支持。 
          8. * Transaction timeout defaults to the default timeout of the underlying transaction system, or to none if time outs are not supported. 
          9. //任何的RuntimeExcetipn將觸發(fā)回滾,任何的checkedException不觸發(fā)回滾。 
          10. * Any RuntimeException triggers rollback,and any checkedException does not. 


          明細(xì)配置:




           

          posted on 2012-04-12 10:14 @趙 閱讀(1748) 評論(0)  編輯  收藏

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


          網(wǎng)站導(dǎo)航:
           
          哥哥最近不是很忙
          主站蜘蛛池模板: 扬州市| 张家川| 潮安县| 临泉县| 辽宁省| 鄱阳县| 肇东市| 武清区| 永顺县| 石棉县| 临城县| 山东省| 台湾省| 繁峙县| 新乡市| 印江| 巴林右旗| 马鞍山市| 宝丰县| 文成县| 克什克腾旗| 长乐市| 浦东新区| 铁力市| 台湾省| 三台县| 遂川县| 湖州市| 双柏县| 内乡县| 清流县| 通渭县| 潍坊市| 晋宁县| 阿鲁科尔沁旗| 榆中县| 巴林左旗| 民权县| 永川市| 岚皋县| 金湖县|