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

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

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

    空間站

    北極心空

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks

    建議查看原帖:http://www.javaeye.com/topic/80697

    開發(fā)目的
    :一個協(xié)同平臺項目,多托管用戶,單門戶系統(tǒng),每個托管用戶對應(yīng)一個單一數(shù)據(jù)庫,要求根據(jù)登陸用戶的單位信息,自動選擇操作數(shù)據(jù)庫;同時,涉及跨庫操作(比如跨庫查詢,跨庫單據(jù)發(fā)送);同時事務(wù)處理必須支持這種多數(shù)據(jù)庫模式,支持一些邏輯性不強的跨庫事務(wù),比如一些數(shù)據(jù)的發(fā)送和接收等

    當然,如果說跨庫操作只涉及到數(shù)據(jù)的發(fā)送和接受的話,也可以通過構(gòu)建專門web service以及通信線程來處理,

    開發(fā)環(huán)境: tomcat4.1,webwork2.2.4,spring2.0.4,hibernate3.1,osworkflow2.8,mysql5.0.19 由于正式發(fā)布的應(yīng)用服務(wù)器是weblogic8.1,所以沒有采用jdk5環(huán)境以及struts2

    準備:

    問題一由于有跨庫操作,而且這種跨庫操作無法預(yù)知,有的跨庫操作完全是在邏輯運行中決定的,比如A托管用戶或則C、D向B托管用戶發(fā)了訂單 ,B回復(fù),這個回復(fù)是根據(jù)訂單發(fā)送者來說的,具體到后臺操作,是無法事先預(yù)知針對具體哪個后臺物理數(shù)據(jù)庫操作的.所以,也就是說,存在在業(yè)務(wù)執(zhí)行過程中切換數(shù)據(jù)庫的情況,傳統(tǒng)的到注入設(shè)置dao類 sessionFactory、靠filter以及Interceptor設(shè)置線程安全的sessionFactory都無法完全達到設(shè)計目的

    問題二事務(wù),本來,我打算用JtaTransactionManager的,除了JtaTransactionManager,在開始時也實在沒想到什么好的辦法, 難道,JtaTransactionManager是唯一選擇么?

    步驟:

    因為問題一,所以系統(tǒng)在資源方面是多sessionFactory并存的方式,也就是多少個托管用戶多少個sessionFactory,當然,事實上,這種應(yīng)用型項目本身并發(fā)訪問量不會太高(什么,很高么,總比不過廣告聯(lián)盟吧,哈哈).不用擔(dān)心多了幾個sessionFactory會對系統(tǒng)或則數(shù)據(jù)庫造成多大影響.

    xml 代碼
     
    1. <bean id="mitDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  
    2.       <property name="driverClass">  
    3.        <value>com.mysql.jdbc.Driver</value>  
    4.       </property>  
    5.       <property name="jdbcUrl">  
    6.        <value>jdbc:mysql://127.0.0.1:3306/mitflow</value>  
    7.       </property>  
    8.       <property name="user">  
    9.        <value>root</value>  
    10.       </property>  
    11.     ...........................  
    12.  </bean>  
    13.   
    14. <bean id="mitSessionFactory"  
    15.   class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
    16.   <property name="mappingResources">  
    17.         ..................................  
    18.     </props>  
    19.   </property>  
    20.     
    21.    <property name="dataSource">  
    22.      <ref local="mitDataSource" />  
    23.    </property>  
    24.  </bean>  

    然后復(fù)制,粘貼,修改jdbcUrl,象網(wǎng)站編輯一樣..

    假設(shè),我配置了兩個sessionFatory ,一個是mitSessionFactory,一個是testSessionFactory,如下:

    xml 代碼
    1. <hibernatesupport>
    2. <itemid="mit"bean="mitSessionFactory"/>
    3. <itemid="test"bean="testSessionFactory"/>
    4. <hibernatesupport>

    這個我自己系統(tǒng)配置的一部分,系統(tǒng)會解析他,從而知曉究竟存在多少個sessionFactory,item's XmlNode中的id可以理解會托管客戶的客戶單位

    編號,當然,這個配置完全可以忽略,直接從ApplicationContext中一樣可以獲取到這樣的信息

    在客戶登陸的時候,系統(tǒng)要記錄下該客戶所屬托管單位,然后通過上面的id找到bean's name ,最后獲取這個sessionFactory,托管單位信息一般

    都是個編號而已跟己方系統(tǒng)的托管用戶管理相結(jié)合,一般是保存這個編號在session里面,也可以象asp.net一樣,記錄在安全憑證里,還不知道JAVA方面有沒有類似實現(xiàn),個人認為asp.net這個方法很值得采用,雖然MS號稱安全系數(shù)+++++這個觀點值得懷疑

    首先建立一個類,HibernateSupport ,存放當前請求線程所需sessionFactory

    java 代碼
     
    1. public class HibernateSupport {  
    2.     public static final String HIBERNATE_SESSIONIDKEY = "com.mit.hibernatesupport.factory.id";  
    3.     private static final Logger logger = Logger.getLogger(HibernateSupport.class);  
    4.     private static ApplicationContext applicationContext ;  
    5.     private static boolean singleSession=true;  
    6.     private static Map factorybeanset;  
    7.     private static ThreadLocal switchhistory;//在切換不同sessionFactory的時候用到  
    8.     private static ThreadLocal idset;//記錄當前默認的托管用戶id,在實際使用中,這個是可以取消掉的  
    9.     private static ThreadLocal curfactory;////當前正在使用的sessionFactory  
    10.     private static ThreadLocal trace;//一個sessionFactory集合,用來記錄這次線程調(diào)用了那些sessionFactory  
    11.     static  
    12.     {  
    13.         idset = new ThreadLocal();  
    14.         curfactory = new ThreadLocal();  
    15.         trace = new ThreadLocal();  
    16.         switchhistory = new ThreadLocal();  
    17.     }  
    18.       
    19.     /** 
    20.      * set current sessionfactory for the Request 
    21.      * @param  ServletContext 
    22.      * @param  the factory's id defined in courser.xml 
    23.      */  
    24.     public static synchronized void setCurrent(ServletContext context,Object id)  
    25.     {  
    26.         if (idset.get()==null)  
    27.         {  
    28.             idset.set(id);  
    29.             if (factorybeanset.containsKey(id))  
    30.             {  
    31.                 if (applicationContext==null)  
    32.                 {  
    33.                      applicationContext =   
    34.                     WebApplicationContextUtils  
    35.                         .getWebApplicationContext(context);  
    36.                 }  
    37.                 curfactory.set((SessionFactory)applicationContext  
    38.                         .getBean((String)factorybeanset.get(id)));  
    39.                 putTrace(idset.get(),(SessionFactory)curfactory.get());  
    40.             }  
    41.         }  
    42.     }  
    43.       
    44.     /** 
    45.      * put the sessionfactory to tracemap 
    46.      * @see COPenSessionInViewFilter release sessionfactory in tracemap  
    47.      * @param  the factory's id defined in courser.xml 
    48.      * @param  hibernate's sessionfactory 
    49.      */  
    50.     private static void putTrace(Object id ,SessionFactory factory)  
    51.     {  
    52.         Map tracemap = null;  
    53.         if (trace.get()==null)  
    54.         {  
    55.             tracemap = new HashMap();  
    56.             trace.set(tracemap);  
    57.         }  
    58.         else  
    59.         {  
    60.             tracemap = (Map)trace.get();  
    61.         }  
    62.         if (!tracemap.containsKey(id))  
    63.         {  
    64.             tracemap.put(id, factory);  
    65.         }  
    66.     }  
    67.       
    68.     /** 
    69.      * switch current sessionfactory  
    70.      * @param  the factory's id defined in courser.xml 
    71.      */  
    72.     public static synchronized void swtichFactory(Object id)  
    73.     {  
    74.         if (!idset.get().equals(id)  )  
    75.         {  
    76.             if (factorybeanset.containsKey(id))  
    77.             {  
    78.                 SessionFactory oldfactory = (SessionFactory)curfactory.get();         
    79.                 SessionFactory newfactory = (SessionFactory)applicationContext  
    80.                 .getBean((String)factorybeanset.get(id));  
    81.                 curfactory.set(newfactory);  
    82.                 pushHistory(oldfactory);  
    83.                 putTrace(id,newfactory);  
    84.                 bindSessionFactory(newfactory);  
    85.             }  
    86.         }  
    87.     }  
    88.       
    89.     /** 
    90.      * restore sessionfactory from queue of switchhistory 
    91.      */  
    92.     public static synchronized void restoreFactory()  
    93.     {  
    94.         SessionFactory factory = popHistory();  
    95.         if (factory!=null)  
    96.         {  
    97.             curfactory.set(factory);  
    98.         }  
    99.     }  
    100.     /** 
    101.      * push old sessionfactory to swithhistory after swtichFactory 
    102.      * @param hibernate's sessionfactory 
    103.      */  
    104.     private static void pushHistory(SessionFactory sessionfactory)  
    105.     {  
    106.         LinkedList list = null;  
    107.         if (switchhistory.get()==null)  
    108.         {  
    109.             list = new LinkedList();  
    110.             switchhistory.set(list);  
    111.         }  
    112.         else  
    113.         {  
    114.             list = (LinkedList)switchhistory.get();  
    115.         }  
    116.         list.add(0,sessionfactory);  
    117.           
    118.     }  
    119.     /** 
    120.      * pop sessionfactory in queue 
    121.      */  
    122.     private static SessionFactory popHistory()  
    123.     {  
    124.         if (switchhistory.get()!=null)  
    125.         {  
    126.             LinkedList list = (LinkedList)switchhistory.get();  
    127.             if (list.size()>0)  
    128.             {  
    129.                 SessionFactory factory = (SessionFactory)list.getFirst();  
    130.                 list.removeFirst();  
    131.                 return factory;  
    132.             }  
    133.         }  
    134.         return null;  
    135.     }  
    136.       
    137.     public static Map getTraceMap()  
    138.     {  
    139.         if (trace.get()!=null)  
    140.         {  
    141.             return (Map)trace.get();  
    142.         }  
    143.         return null;  
    144.     }  
    145.       
    146.     public static SessionFactory getCurrentFactory()  
    147.     {  
    148.         return (SessionFactory)curfactory.get();  
    149.     }  
    150.       
    151.     public static synchronized void release()  
    152.     {  
    153.         idset.set(null);  
    154.         curfactory.set(null);  
    155.         switchhistory.set(null);  
    156.         trace.set(null);  
    157.     }  
    158.       
    159.     /** 
    160.      * °ó¶¨sessionFactoryµ½springµÄ×ÊÔ´¹ÜÀí 
    161.      * @param hibernate's sessionfactory 
    162.      */  
    163.     private static synchronized boolean bindSessionFactory(SessionFactory sessionFactory)  
    164.     {  
    165.         boolean participate=false;;  
    166.         if (singleSession) {  
    167.             // single session mode  
    168.             if (TransactionSynchronizationManager.hasResource(sessionFactory)) {  
    169.                 // Do not modify the Session: just set the participate flag.  
    170.                 participate = true;  
    171.             }  
    172.             else {  
    173.                 logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");  
    174.                 Session session = getSession(sessionFactory);  
    175.                 if (!TransactionSynchronizationManager.hasResource(sessionFactory))  
    176.                 {     
    177.                     TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));  
    178.                 }  
    179.             }  
    180.         }  
    181.         else {  
    182.             // deferred close mode  
    183.             if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {  
    184.                 // Do not modify deferred close: just set the participate flag.  
    185.                 participate = true;  
    186.             }  
    187.             else {  
    188.                 SessionFactoryUtils.initDeferredClose(sessionFactory);  
    189.             }  
    190.         }  
    191.         return participate;  
    192.     }  
    193.       
    194.     //see SessionFactoryUtils  
    195.     private static  Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {  
    196.         Session session = SessionFactoryUtils.getSession(sessionFactory, true);  
    197.         FlushMode flushMode = FlushMode.COMMIT;  
    198.         if (flushMode != null) {  
    199.             session.setFlushMode(flushMode);  
    200.         }  
    201.         return session;  
    202.     }  
    203.   
    204.     public static synchronized void initSessionFactory(Map res,Class loadclass)  
    205.     {  
    206.         factorybeanset =res;  
    207.     }  
    208.   
    209.       
    210. }  
    HibernateSupport這個類其他方法可以不管,暫時關(guān)注setCurrent這個方法

    java 代碼
    1. if (idset.get()==null)
    2. {
    3. idset.set(id);
    4. if (factorybeanset.containsKey(id)) //factorybeanset包含的就是我自己系統(tǒng)配置中那一部分,key就是id,,value就是sessionFactory 在spring環(huán)境中的beanName
    5. {
    6. if (applicationContext==null)
    7. {
    8. applicationContext =WebApplicationContextUtils.getWebApplicationContext(context);
    9. }
    10. curfactory.set((SessionFactory)applicationContext.getBean((String)factorybeanset.get(id)));//設(shè)置當前的sessionFactory
    11. putTrace(idset.get(),(SessionFactory)curfactory.get());//put到當前線程的一個記錄集
    12. }
    13. }
    然后,就要修改spring關(guān)于hibernate的一些支持類了,當然,也可以選擇重新寫一套dao支持類,呵呵,不過,顯然,在spring基礎(chǔ)上做一些小修改代價更小 HibernateAccessorHibernateTemplate的基類)以及HibernateTransactionManager都是靠注入方式獲取一個sessionFactory,顯然,這套不適合了,修改之

    sessionFactory好做,配置在spring或則單獨拿出來處理都可以,但是spring的HibernateDaoSupport 必須綁定一個sessionFactory,當然,我們完全可以寫一個自己的HibernateDaoSupport ,但是既然用了spring的事務(wù)管理而又不想多花時間,還是將就改改用吧

    java 代碼
    1. private SessionFactory sessionFactory;
    2. publicvoid setSessionFactory(SessionFactory sessionFactory) {
    3. this.sessionFactory = sessionFactory;
    4. }

    去掉HibernateAccessorHibernateTransactionManager中的上述兩段代碼,當然,也別忘了斃掉兩個類中的

    afterPropertiesSet方法中那些檢查代碼

    然后 ,ant打包就可以了,如果不想修改spring的代碼,也可以單獨把這幾個類提出來另建jar,我是單獨提出來新建的,比如HibernateTransactionManager我改名成CHibernateTransactionManager,其他類似,但是包名必須是org.springframework.orm.hibernate3 ,誰也不想這么做,可是誰讓sessionFactoryUtils中一個closexxxx方法沒定義成public了??

    如果想變更sessionFactoryUtils,奉勸算了吧..

    然后可以做測試了,首先,部署測試的daoservice,先是事務(wù)部署

    xml 代碼
    1. <beanid="transactionManager"
    2. class="com.mit.web.hibernate.CHibernateTransactionManager"/>
    3. <beanid="transres"class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
    4. <propertyname="properties">
    5. <props>
    6. <propkey="load*">PROPAGATION_REQUIRED,readOnlyprop>
    7. <propkey="save*">PROPAGATION_REQUIREDprop>
    8. <propkey="delete*">PROPAGATION_REQUIREDprop>
    9. <propkey="find*">PROPAGATION_REQUIRED,readOnlyprop>
    10. <propkey="query*">PROPAGATION_REQUIRED,readOnlyprop>
    11. <propkey="create*">PROPAGATION_REQUIREDprop>
    12. <propkey="set*">PROPAGATION_REQUIRED,readOnlyprop>
    13. <propkey="execute*">PROPAGATION_REQUIREDprop>
    14. props>
    15. property>
    16. bean>
    17. <beanid="transactionInterceptor"class=span
    家里網(wǎng)絡(luò)環(huán)境不好,本來想修改下里面的代碼格式,結(jié)果成了半截子,我轉(zhuǎn)到回復(fù)里面來寫把3
    事務(wù)配置如下:
    Java代碼 復(fù)制代碼
    1.  <bean id="transactionManager"     
    2.          class="com.mit.web.hibernate.CHibernateTransactionManager"/>   
    3.   
    4. <bean id="transres" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">   
    5.     <property name="properties">   
    6.         <props>   
    7.             <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>   
    8.             <prop key="save*">PROPAGATION_REQUIRED</prop>   
    9.             <prop key="delete*">PROPAGATION_REQUIRED</prop>   
    10.             <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>   
    11.             <prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>   
    12.             <prop key="create*">PROPAGATION_REQUIRED</prop>   
    13.             <prop key="set*">PROPAGATION_REQUIRED,readOnly</prop>   
    14.             <prop key="execute*">PROPAGATION_REQUIRED</prop>   
    15.         </props>   
    16.     </property>   
    17. </bean>   
    18.   
    19. <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">     
    20.        <property name="transactionManager" ref="transactionManager"/>     
    21.      <property name="transactionAttributeSource"><ref local="transres"/></property>   
    22.    </bean>     
    23.      
    24.    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">     
    25.  <property name="beanNames"><value>*Service</value></property>   
    26.        <property name="interceptorNames">     
    27.            <list>     
    28.                <value>transactionInterceptor</value>     
    29.            </list>     
    30.        </property>     
    31.    </bean>     
    32.     
    33.    <bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">     
    34.      <property name="transactionInterceptor" ref="transactionInterceptor"/>     
    35.    </bean>   

    我把事務(wù)配置在service層,事務(wù)管理采用的是我修改后的HibernateTransactionManager ,他不在要求sessionFactory的注入了
    以下是測試的dao類和service類配置
    Java代碼 復(fù)制代碼
    1. <bean id="personDao" class="com.mit.web.action.PersonDaoImpl"/>    
    2. <bean id="personService" class="com.mit.web.action.PersonServiceImpl">    
    3.     <property name="personDao">    
    4.      <ref bean="personDao"/>    
    5.     </property>    
    6.  </bean>    
    7.     
    8. <bean id="departDao" class="com.mit.web.action.DepartDaoImpl"/>    
    9. <bean id="departService" class="com.mit.web.action.DepartServiceImpl">    
    10.     <property name="personService">    
    11.         <ref bean="personService"/>    
    12.     </property>    
    13.     <property name="departDao">    
    14.         <ref bean="departDao"/>    
    15.     </property>    
    16. </bean>   

    具體代碼不寫了,大概如下:
    Java代碼 復(fù)制代碼
    1. public class PersonDaoImpl extends CHibernateDaoSupport implements PersonDao;    
    2. public class PersonServiceImpl implements PersonService;    
    3. public class DepartDaoImpl extends CHibernateDaoSupport implements DepartDao;    
    4. public class DepartServiceImpl implements DepartService;   

    測試代碼的目的是將兩個實體類分別存放到mit和test庫,假設(shè)默認用戶是mit這個托管庫的,這個方法就寫在DepartServiceImpl類里面
    Java代碼 復(fù)制代碼
    1. public class DepartServiceImpl implements DepartService {    
    2. private DepartDao dao;    
    3. private PersonService service;    
    4.  ..............................    
    5.  public void executeTest(Depart depart,Person person)    
    6.  {    
    7.     dao.save(depart);    
    8.     HibernateSupport.switchFactory("test");    
    9.     service.save(person);    
    10.     HibernateSupport.restoreFactory();    
    11. }    
    12.  ..............................   

    上面代碼中將depart對象存到mit庫,而將person對象存到test庫中.

    事務(wù) 事務(wù) ,沒看見特別事務(wù)設(shè)置? 其實事務(wù)已經(jīng)在運行了

    如前面配置,事務(wù)我配置在了service層,那么當executeTest執(zhí)行時,會啟動針對mit庫的事務(wù)(前面我們改了HibernateTransactionManager的sessionFactory獲取方式),

    dao.save(depart);//然后保存depart到mit庫

    HibernateSupport.switchFactory("test");//切換庫到test

    service.save(person);//調(diào)用personService的save方法,這也是個service,所以也會產(chǎn)生一個事務(wù),而此時HibernateSupport.getCurrentFactory返回的sessionFactory已經(jīng)是test庫的了,所以,spring事務(wù)管理發(fā)現(xiàn)上下文中并沒有針對test的事務(wù),于是,會重新啟動一個新的事務(wù),這個service.save(person);方法執(zhí)行完后,這個事務(wù)將會提交

    HibernateSupport.restoreFactory();//切換回默認數(shù)據(jù)庫

    整個方法執(zhí)行完后,針對mit的事務(wù)將會被提交

    [color=green]如果service.save(person);發(fā)生異常,這兩個事務(wù)就會被提交,一個簡單跨庫事務(wù)控制完成[color=green]

    但是,問題也隨之而來,如果在 HibernateSupport.restoreFactory();后,又進行了一些邏輯操作,那么發(fā)生異常時,而由于 service.save(person);這個事務(wù)已經(jīng)被提交,也就是說,針對test的事務(wù)已經(jīng)提交不會回滾了,這是個非常嚴重的問題。。

    其實,也有解決方法,就是延遲提交,具體實現(xiàn)方式以后講述

    跨庫事務(wù)之延遲提交
    延遲事務(wù),就是將事務(wù)延后提交,延遲的時間由事務(wù)管理器掌握。在我的系統(tǒng)中,只有跨庫操作涉及到延遲提交,針對這種操作,我設(shè)計了一個基本的執(zhí)行模型。就是如果一個邏輯中存在多個事務(wù),將全部放到邏輯執(zhí)行完以后提交,那么,既然如此,開始吧
    PlatformTransactionManager是spring平臺相關(guān)事務(wù),比如HibernateTransactionManager都是繼承于此類,為了達到延遲提交的目的,可以在AbstractPlatformTransactionManagershang上做修改達到目的
    首先,說一下在spring中,通常的一個事務(wù)流程,
    流程如下:初始化Transaction B,如果發(fā)現(xiàn)前面有其他Transaction ,比如 Transaction A,那么掛起TransactionA ,然后啟動事務(wù) ,當邏輯執(zhí)行完后 ,commit,恢復(fù)掛起事務(wù)A,然后清除同步對象以及其他資源,如果執(zhí)行發(fā)生異常,當然,異常發(fā)生后 rollback
    延遲提交的設(shè)計思想是將事務(wù)都暫存在一個threadlocal的LIST里面,等邏輯執(zhí)行完以后,再統(tǒng)一提交,那么首先在AbstractPlatformTransactionManager中設(shè)置一個threadlocal對象
    Java代碼 復(fù)制代碼
    1. private ThreadLocal lazytrace = new ThreadLocal();  

    LazyTransactionStatus用來管理需要延遲提交的事務(wù)
    Java代碼 復(fù)制代碼
    1. private static class LazyTransactionStatus   
    2. {   
    3.     private java.util.List transliat;   
    4.     private int transnum;//代表未提交事務(wù)數(shù)量   
    5.        
    6.     public LazyTransactionStatus()   
    7.     {   
    8.         transliat= new java.util.ArrayList();   
    9.         transnum=0;   
    10.     }   
    11.        
    12.     public void newLazy()   
    13.     {   
    14.         transnum++;   
    15.     }   
    16.        
    17.     public void push(TransactionStatus trasobj)   
    18.     {      
    19.         objmap.add(trasobj);   
    20.     }   
    21.        
    22.     public void removeLazy(TransactionStatus trasobj)   
    23.     {   
    24.         transnum--;   
    25.     }   
    26.        
    27.     public boolean canCommit()   
    28.     {   
    29.         if (transnum<1)   
    30.         {   
    31.             return true;   
    32.         }   
    33.         else  
    34.             return false;   
    35.     }   
    36.        
    37.     public java.util.List getTransactionObjs()   
    38.     {   
    39.         return transliat;   
    40.     }   
    41. }   

    這就是local對象的存儲內(nèi)容.translist存放當前執(zhí)行中的TransactionStatus實例
    TransactionStatus顧名思義,事務(wù)狀態(tài),包含了事務(wù)、掛起資源等一系列信息
    然后以事務(wù)提交為例
    然后在AbstractTransactionManager增加如下兩個方法
    Java代碼 復(fù)制代碼
    1. public final boolean isCommit(TransactionStatus status)   
    2. {   
    3.     if (lazytrace.get()!=null)   
    4.     {   
    5.         LazyTransactionStatus lazystatus = (LazyTransactionStatus)lazytrace.get();   
    6.         lazystatus.removeLazy(status);   
    7.         return lazy.canCommit();   
    8.     }   
    9.     return true;   
    10. }   
    11.   
    12. protected void begin(Object transaction, TransactionDefinition definition)   
    13. {   
    14.     doBegin(transaction,definition);   
    15.     LazyTransactionStatus lazystatus = null;   
    16.     if (lazytrace.get()==null)   
    17.     {   
    18.         lazystatus = new LazyTransactionStatus();   
    19.         lazytrace.set(lazystatus);   
    20.     }   
    21.     else  
    22.     {   
    23.         lazystatus = (LazyTransactionStatus)lazytrace.get();   
    24.     }   
    25.     lazystatus.newLazy();   
    26. }   
    27.   
    28. public final void registerTraceStatus(TransactionStatus status)   
    29. {   
    30.     LazyTransactionStatus lazystatus = null;   
    31.     if (lazytrace.get()==null)   
    32.     {   
    33.         lazystatus = new LazyTransactionStatus();   
    34.         lazytrace.set(lazystatus);   
    35.     }   
    36.     else  
    37.     {   
    38.         lazystatus = (LazyTransactionStatus)lazytrace.get();   
    39.     }   
    40.     lazystatus.push(status);   
    41. }  

    begin ,當一個事務(wù)開始時,將LazyTransactionStatus的transnum+1,表示又多了個剛開始,還未提交的事務(wù)
    registerTraceStatus發(fā)生在commit的時候,注冊這個事務(wù)到LazyTransactionStatus,同時,
    注意 transnum表示的是未提交事務(wù)數(shù)量,所以當事務(wù)管理器執(zhí)行commit表示要提交一個事務(wù)后,transnum將減一,如果減一后發(fā)現(xiàn)transnum<1,表示所有事務(wù)都提交了,那么,將所有事務(wù)提交。否則,不提交,繼續(xù)等待...
    關(guān)系如下:
    begin->transnum+1 表示新事務(wù)誕生
    registerTraceStatus(發(fā)生在commit的時候)->將準備提交的TransStatus放到LazyTransactionStatus,是的,這個事務(wù)要提交了,來吧,先注冊一下
    緊接著
    isCommit()->將transnum-1,如果發(fā)現(xiàn)transnum小于1 ,表示鬧夠了,可以都提交滾蛋了
    注意 ,transnum與LazyTransactionStatus的translist的鏈表長度在執(zhí)行commit的時候是反方向發(fā)展的 一個增,一個減
    好了,首先是注冊事務(wù)數(shù)量,不用管了,在事務(wù)開始時begin方法它自己會調(diào)用了,
    然后是修改AbstractPlatformTransactionManager的commit方法

    Java代碼 復(fù)制代碼
    1. public final void commit(TransactionStatus txstatus) throws TransactionException {   
    2.     this.registerTraceStatus(txstatus);   
    3.     if (this.isCommit(txstatus))   
    4.     {   
    5.         int error = 0;   
    6.         LazyTransactionStatus lazystatus = (LazyTransactionStatus)lazytrace.get();   
    7.         List statuslist = lazystatus.getTransactionObjs();   
    8.         for (int i=0;i<statuslist.size();i++)   
    9.         {   
    10.             try  
    11.             {   
    12.                 TransactionStatus status = (TransactionStatus)statuslist.get(i);   
    13.                 if (status.isCompleted()) {   
    14.                     error++;   
    15.                     continue;   
    16.                     //throw new IllegalTransactionStateException(   
    17.                     //      "Transaction is already completed - do not call commit or rollback more than once per transaction");   
    18.                 }   
    19.            
    20.                 DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;   
    21.                 if (defStatus.isLocalRollbackOnly()) {   
    22.                     if (defStatus.isDebug()) {   
    23.                         logger.debug("Transactional code has requested rollback");   
    24.                     }   
    25.                     processRollback(defStatus);   
    26.                     error++;   
    27.                     continue;   
    28.                 }   
    29.                 if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {   
    30.                     if (defStatus.isDebug()) {   
    31.                         logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");   
    32.                     }   
    33.                     processRollback(defStatus);   
    34.                     // Throw UnexpectedRollbackException only at outermost transaction boundary   
    35.                     // or if explicitly asked to.   
    36.                     if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {   
    37.                         //throw new UnexpectedRollbackException(   
    38.                                 //"Transaction rolled back because it has been marked as rollback-only");   
    39.                         error++;   
    40.                         continue;   
    41.                     }   
    42.                     continue;   
    43.                 }   
    44.                    
    45.                 processCommit(defStatus);   
    46.             }   
    47.             catch (Exception ex)   
    48.             {   
    49.                 error++;   
    50.                 ex.printStackTrace();   
    51.                 continue;   
    52.             }   
    53.                
    54.         }   
    55.         lazytrace.set(null);   
    56.         if (error>0)   
    57.             throw new IllegalTransactionStateException(   
    58.                         "Not commit all transaction");   
    59.     }   
    60. }  

    this.registerTraceStatus(txstatus);//事務(wù)提交了,成了嫌疑犯,拖到threadlocal的LazyTransactionStatus監(jiān)獄里面先關(guān)起來
    if (isCommit()) //看看監(jiān)獄的事務(wù)是不是滿了,如果滿了,就可以全放了
    LazyTransactionStatus lazystatus = (LazyTransactionStatus)lazytrace.get();
    List statuslist = lazystatus.getTransactionObjs();
    for (int i=0;i<statuslist.size();i++)
    {
                              ........
                             processCommit(defStatus);
    //看來真的滿了,都放了吧
    回滾道理是一樣的,不過不用判斷了,直接全部放出來讓他們滾吧
    當然,目前這個實現(xiàn)只是個模型,真要實際應(yīng)用,還需要做進一步封裝,實際做,我用了OpenSessionInViewFilter,我已經(jīng)做過測試,測試了了OpenSessionInViewFilter中singleSession為true和false兩種情況,測試都通過了,呵呵
    posted on 2008-11-13 11:25 蘆葦 閱讀(5766) 評論(0)  編輯  收藏 所屬分類: Hibernate
    主站蜘蛛池模板: 特级aaaaaaaaa毛片免费视频| 亚洲福利视频一区二区| 亚洲黄色在线视频| 精品国产免费一区二区| 欧美大尺寸SUV免费| 久久WWW免费人成人片| 欧美最猛性xxxxx免费| 无码中文在线二区免费| 污污视频免费观看网站| 免费被黄网站在观看| 理论片在线观看免费| 亚洲AV乱码一区二区三区林ゆな| 久久久久免费看黄A片APP| 污污视频免费观看网站| 亚洲一级毛片中文字幕| 亚洲国产中文字幕在线观看| 日本成年免费网站| 国产精品玖玖美女张开腿让男人桶爽免费看 | 亚洲∧v久久久无码精品| 啦啦啦中文在线观看电视剧免费版| 黄色视屏在线免费播放| 亚洲熟伦熟女专区hd高清| 亚洲国产精品高清久久久| 国产午夜免费秋霞影院| 成人免费视频网站www| 中文字幕手机在线免费看电影| 学生妹亚洲一区二区| 亚洲视频在线观看免费| 亚洲午夜精品久久久久久浪潮| 成人免费视频88| 亚洲精品在线免费看| 中文字幕在线免费看线人| 色偷偷尼玛图亚洲综合| 亚洲精品第一国产综合精品| 久久亚洲中文字幕精品一区四| 成人男女网18免费视频| 亚洲视频在线免费观看| 巨胸喷奶水视频www免费视频| 女bbbbxxxx另类亚洲| 亚洲精品无码少妇30P| 久久精品国产亚洲AV忘忧草18 |