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

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

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

    posts - 66,  comments - 11,  trackbacks - 0
    package com.hibernate.higherApplication;

    import java.util.Iterator;
    import java.util.List;
    import java.util.Set;

    import junit.framework.TestCase;

    import org.hibernate.Criteria;
    import org.hibernate.Hibernate;
    import org.hibernate.HibernateException;
    import org.hibernate.Query;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.criterion.Expression;

    public class DurationOperator extends TestCase {
        
    private SessionFactory sessionFactory = null;
        
    private Session session = null;
        
    /**
         * 初始化資源
         
    */
        
    protected void setUp() throws Exception {
            
    try {
                
    //加載類路徑下的hibernate.cfg.xml文件
                Configuration config = new Configuration().configure();
                
    //創建sessionFactory對象
                sessionFactory = config.buildSessionFactory();
                
    //創建session
                session = sessionFactory.openSession();
            } 
    catch (HibernateException e) {
                e.printStackTrace();
            }
        }
        
    /**
         * load/get方法均可以根據指定的實體類和id從數據庫讀取記錄,并返回與之對應的實體對象。
         * 區別在于:
         * 1、如果未發現符合條件的記錄,get方法返回null,而load方法拋出一個ObjectNotFoundException
         * 2、load方法可以返回實體的代理類實例,而get方法永遠直接返回實體類。
         * 3、load方法可以充分利用內部緩存和二級緩存中的現有數據,而get方法則僅僅在內部緩存中進行數據查找,如果
         * 沒有發現數據,將越過二級緩存,直接調用SQL完成數據讀取。
         *
         
    */
        
    public void loadOrGetData(){
            TUser user 
    = (TUser)session.load(TUser.class,new Integer(1));
        }
        
    /**
         * 查詢性能往往是一系統性能表現的一個重要方面。
         * query.list方法通過一條select SQL實現了查詢操作,而iterate方法,則執行了3次selectSQL,第一次獲取了所有符合條件的記錄
         * 的id,之后,在根據各個id從庫表中讀取對應的哦記錄,這是一個典型的N+1次查詢問題。
         * 
         * 我們進行query.list數據查詢時,即使緩存中已經有一些符合條件的實體對象存在,我們也無法保證這些數據就是庫表中所有符合條件的數據。假設
         * 第一次查詢條件是age>25,隨即緩存中就包括了所有age>25的user數據;第二次查詢條件為age>20,此時緩存中雖然包含了滿足age>25d的
         * 數據,但這些并不是滿足條件age>20的全部數據
         * 因此,query.list方法還是需要執行一次select sql以保證查詢結果的完整性(iterate方法通過首先查詢獲取所有符合條件記錄的id,以此保證
         * 查詢結果的完整性)。
         * 因此,query.list方法實際上無法利用緩存,它對緩存只寫不讀。而iterate方法則可以充分發揮緩存帶來的優勢,如果目標數據只讀或者讀取相對
         * 較為頻繁,通過這種機制可以大大減少性能上的損耗。
         
    */
        
    public void queryForList(){
            String hql 
    = "from TUser where age>?";
            Query query 
    = session.createQuery(hql);
            query.setInteger(
    1,1);
            
            List list 
    = query.list();
            
            
    for(int i=0;i<list.size();i++){
                TUser user 
    = (TUser)list.get(i);
                System.out.println(
    "User age:"+user.getAge());
            }
        }
        
    public void queryForIterate(){
            String hql 
    = "from TUser where age>?";
            Query query 
    = session.createQuery(hql);
            query.setInteger(
    1,1);
            
            Iterator it 
    = query.iterate();
            
            
    while(it.hasNext()){
                TUser user 
    = (TUser)it.next();
                System.out.println(
    "User age:"+user.getAge());
            }
        }
        
    /**
         * 大數據量的批量讀取(10W條)
         * 解決方案:結合iterate方法和evict方法逐條對記錄進行處理,將內存消耗保持在可以接受的范圍之內。
         * 在實際開發中,對于大批量數據處理,還是推薦采用SQL或存儲過程實現,以獲得較高的性能,并保證系統平滑運行。
         
    */
        
    public void bigDataRead(){
            String hql 
    = "from TUser where age>?";
            Query query 
    = session.createQuery(hql);
            query.setInteger(
    "age"1);
            Iterator it 
    = query.iterate();
            
            
    while(it.hasNext()){
                TUser user 
    = (TUser)it.next();
                
    //將對象從一級緩存中移除
                session.evict(user);
                
    //二級緩存可以設定最大數據緩存數量,達到峰值時會自動對緩存中的較老數據進行廢除,但是我們這里還是通過
                
    //編碼指定將對象從二級緩存中移除,這有助保持緩存的數據有效性。
                sessionFactory.evict(TUser.class,user.getId());
            }
        }
        
    /**
         * Query Cache彌補了find方法的不足,QueryCache中緩存的SQL及其結果及并非永遠存在,當Hibernate發現此SQL對應的庫表發生變動,
         * 會自動將Query Cache中對應表的SQL緩存廢除。因此Query Cache只在特定的情況下產生作用:
         * 1、完全相同的select SQL重復執行。
         * 2、在2次查詢之間,此select SQL對應的庫表沒有發生過改變。
         
    */
        
    public void queryForQueryCache(){
            String hql 
    = "from TUser where age>?";
            Query query 
    = session.createQuery(hql);
            query.setInteger(
    11);
            
    //除了在這里設置QueryCache外,還要在hibernate.cfg.xml中進行設置
            
    //<property name="hibernate.cache.use_query_cache">true</property>
            query.setCacheable(true);
            List userList 
    = query.list();
        }
        
    /**
         * 所謂延遲加載,就是在需要數據的時候,才真正執行數據加載操作。
         * 延遲加載實現主要針對:
         * 1、實體對象:通過class的lazy屬性,我們可以打開實體對象的延遲加載功能。
         * 2、集合
         
    */
        
    public void queryForEntityLazy(){
            Criteria criteria 
    = session.createCriteria(TUser.class);
            criteria.add(Expression.eq(
    "name","Erica"));
            
            List userList 
    = criteria.list();
            TUser user 
    = (TUser)userList.get(0);
            
    //雖然使用了延遲加載,但是我們可以通過hibernate的初始化方法進行強制加載,這樣即使session關閉之后,關聯的對象仍讓可以使用
            Hibernate.initialize(user.getAddresses());
            
            System.out.println(
    "User name=>"+user.getAge());
            
            Set hset 
    =user.getAddresses();
            TAddresses addr 
    = (TAddresses)hset.toArray()[0];
            System.out.println(addr.getAddress());
            
            session.close();
        }
        
    /**
         * 關閉資源
         
    */
        
    protected void tearDown() throws Exception {
            
    try{
                session.close();
            }
    catch(HibernateException e){
                e.printStackTrace();
            }
        }

    }
    posted @ 2010-01-02 15:27 王永慶 閱讀(363) | 評論 (0)編輯 收藏
      基于Java的緩存實現,最簡單的方式莫過于對集合類數據類型進行封裝。Hibernate提供了基于Hashtable的緩存實現機制,不過,由于其性能和功能上的局限,僅供開發調試中使用。同時,Hibernate還提供了面向第三方緩存實現的接口,如:
    HashTable--------------------------------net.sf.hibernate.cache.HashtableCacheProvider
    1、JSC
    2、EHCache->默認的二級Cache實現。--------net.sf.encache.hibernate.Provider
    3、OSCache-------------------------------net.sf.hibernate.cache.OSCacheProvider
    4、JBoss Cache->分布式緩存---------------net.sf.hibernate.cache.TreeCacheProvider
    5、SwarmCache----------------------------net.sf.hibernate.cache.SwarmCacheProvider
    相對于JSC而言,EHCache更加穩定,并具備更好的混存調度性能,其缺陷是目前還無法做到分布式緩存。
    首先設置hibernate.cfg.xml然后設置ehcache.xml最后設置緩存策略。

      緩存同步策略決定了數據對象在緩存中的存取規則。為了使得緩存調度遵循正確的應用級事物隔離機制,我們必須為每個實體類指定相應的緩存同步策略。Hibernate提供4種內置的緩存同步策略:
    1、read-only:只讀。對于不會發生改變的數據,可使用只讀型緩存。
    2、nonstrict-read-write:如果程序對并發訪問下的數據同步要求不是非常嚴格,且數據更新操作頻率較低,可以采用本選項。
    3、read-write:嚴格可讀寫緩存。
    4、transactional:事務型緩存,必須運行在JTA事物環境中。

      JDBC事物由Connection管理,也就是說,事務管理實際上是在JDBC Connection中實現。事務周期限于Connection的生命周期之類。同樣,對于基于JDBC Transaction的Hibernate事務管理機制而言,事物管理在Session所以托的JDBCConnection中實現,事務周期限于Session的生命周期。
      JTA事物管理則由JTA容器實現,JTA容器對當前加入事物的眾多Connection進行調度,實現其事務性要求。JTA的事物周期可橫跨多個JDBC Connectin生命周期。同樣對于基于JTA事務的Hibernate而言,JTA事物橫跨多個Session.

      Hibernate支持2種鎖機制:即通常所說的悲觀鎖和樂觀鎖。
      悲觀鎖的實現,往往依靠數據庫提供的鎖機制。典型的悲觀鎖調用:
      select * from account where name=="Erica" for update
    package com.hibernate.higherApplication;

    import java.util.List;

    import junit.framework.TestCase;

    import org.hibernate.Criteria;
    import org.hibernate.HibernateException;
    import org.hibernate.LockMode;
    import org.hibernate.Query;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.criterion.Expression;

    public class LockOperator extends TestCase {
        
    private Session session = null;
        
    /**
         * 初始化資源
         
    */
        
    protected void setUp() throws Exception {
            
    try {
                
    //加載類路徑下的hibernate.cfg.xml文件
                Configuration config = new Configuration().configure();
                
    //創建sessionFactory對象
                SessionFactory sessionFactory = config.buildSessionFactory();
                
    //創建session
                session = sessionFactory.openSession();
            } 
    catch (HibernateException e) {
                e.printStackTrace();
            }        
        }
        
    /**
         * 悲觀鎖
         * Hibernate的加鎖模式有:
         * 1、LockMode.NONE:無鎖機制
         * 2、LockMode.WRITE:Hibernate在Insert和Update記錄的時候會自動獲取
         * 3、LockMode.READ:Hibernate在讀取記錄的時候會自動獲取
         * 上述3種鎖機制為了保證update過程中對象不會被外界修改,在目標對象上加鎖,與數據庫無關
         * 4、LockMode.UPGRADE:利用數據庫的for update子句加鎖
         * 5、LockMode.UPGRADE_NOWAIT:oracle的特定實現
         * 注意:只有在查詢開始之前設定加鎖,才會真正通過數據庫的鎖機制進行加鎖處理。
         
    */
        
    public void addPessimismLock(){
            String hqlStr 
    = "from TUser as user where user.name='Erica'";
            Query query 
    = session.createQuery(hqlStr);
            query.setLockMode(
    "user",LockMode.UPGRADE);//多所有返回的user對象加鎖
            List userList = query.list();//執行查詢
        }
        
    /**
         * 樂觀鎖
         * 數據版本:即為數據增加一個版本標識,在基于數據庫表的版本解決方案中,一般是通過為數據庫表增加一個version字段來實現。
         * 讀取出數據時,將此版本號一同讀出,之后更新時,對此版本號加1.此時,將提交數據的版本數據與數據庫對應記錄的當前版本信息
         * 進行比對,如果提交的數據版本號大于數據庫表當前版本號,則予以更新,否則認為是過期數據。
         * 
         * Hibernate在其數據訪問引擎中內置了樂觀鎖實現。如果不考慮外部系統對數據庫的更新操作,利用Hibernate提供的透明化樂觀鎖
         * 實現,將大大提升我們的生產力。見配置文件T_USER.hbm.xml
         * 樂觀鎖機制避免了長事務中的數據加鎖開銷,大大提升了大并發量下的系統整體性能表象。
         *
         
    */
        
    public void addOptimismLock(){
            Criteria criteria 
    = session.createCriteria(TUser.class);
            criteria.add(Expression.eq(
    "name","Erica"));
            
            List userList 
    = criteria.list();
            TUser user 
    = (TUser)userList.get(0);
            
            Transaction tx 
    = session.beginTransaction();
            user.setVersion(
    1);
            tx.commit();
        }
        
    /**
         * 關閉資源
         
    */
        
    protected void tearDown() throws Exception {
            
    try{
                session.close();
            }
    catch(HibernateException e){
                e.printStackTrace();
            }
        }
        
    }

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
    >
    <hibernate-mapping>
        
    <!-- 
            none:無樂觀鎖
            version:通過版本機制實現樂觀鎖
            dirty:通過檢查發生變動過的屬性實現樂觀鎖
            all通過檢查所有屬性實現樂觀鎖
         
    -->
        
    <class
            
    name="org.hibernate.sample.TUSER"
            table
    ="t_user"
            dynamic-update
    ="true"
            dynamic-insert
    ="true"
            optimistic-lock
    ="version"
            lazy
    ="true"
            
    >
            
    <id
            
    name="id"
            column
    ="id"
            type
    ="java.lang.Integer"
            
    >
                
    <generator class="native">
                
    </generator>
            
    </id>
            
    <version name="version" column="version" type="java.lang.Integer">
            
    </version>
            
    <set name="addresses"
                 table
    ="t_address"
                 lazy
    ="true"
                 inverse
    ="false"
                 cascade
    ="all"
            
    >
                
    <key
                    
    column="user_id"
                
    >
                
    </key>
                
    <one-to-many class=""/>
            
    </set>
        
    </class>
    </hibernate-mapping>


    posted @ 2010-01-02 15:25 王永慶 閱讀(561) | 評論 (0)編輯 收藏
        實體對象,特指Hibernate O/R映射關系中的域對象。實體對象生命周期中的3種狀態
        1、Transient(自由狀態):所謂Transient,即實體對象在內存中的自由存在,它與數據庫中的記錄無關。
        2、Persistent(持久狀態):即實體對象處于由Hibernate框架所管理的狀態。
        3、Detached(游離狀態):處于Persistent狀態的對象,其對應的Session實例關閉之后,那么,此對象就處于"Detached"狀態。
        Transient狀態的user對象與庫表的數據缺乏對應關系,而Detached狀態的user對象,卻在庫表中存在對應的記錄,只不過由于Detached對象脫離了session這個數據操作平臺,其狀態的變化無法更新到庫表中的對應記錄。
        處于Transient和Detached狀態的對象統稱為值對象(VO),而處于Persistent狀態的對象稱為持久對象(PO).這是站在實體對象是否被納入Hibernate實體管理容器的立場加以區分的,非管理的實體對象統稱為VO,而被管理的實體對象稱為PO.
    VO與PO的主要區別在于:
    1、VO是相對獨立的實體對象,處于非管理狀態。
    2、PO是由Hibernate納入其實體管理容器的對象,它代表了與數據庫中某條記錄對應的Hibernate實體,PO的變化在事務提交時將反映到實際數據庫中
    3、如果一個PO與其對應的Session實例分離,那么此時,它又會變成一個VO。

        不覆蓋equals/hashCode方法的情況下我們要面對的問題:實體對象的跨session識別。解決辦法一個是實現所謂的值比對,即在equals/hashCode方法中,對實體類的所有屬性值進行比對.除了值比對,還有另外一種基于業務邏輯的對象判定方式業務關鍵信息判定。

        tx.commint();方法中會調用session.flush()方法,在flush()方法中會執行2個主要任務
    1、flushEverything();//刷新所有數據
    2、execute(0);//執行數據庫SQL完成持久化動作。

        數據緩存:在特定硬件基礎上緩存往往是提升系統性能的關鍵因素。緩存是數據庫數據在內存中的臨時容器,它包含了庫表數據在內存中的臨時拷貝,位于數據庫與數據訪問層之間。ORM在進行數據讀取時,會根據其緩存管理策略,首先在緩存中查詢,如果在緩存中發現所需數據,則直接以此數據作為查詢結果加以利用,從而避免了數據庫調用的性能開銷。
        相對內存操作而言,數據庫調用是一個代價高昂的過程,對于典型企業及應用結構,數據庫往往與應用服務器位于不同的物理服務器,這也就意味著每次數據庫訪問都是一次遠程調用,Socket的創建與銷毀,數據的打包拆包,數據庫執行查詢命令,網絡傳輸上的延時,這些消耗都給系統整體性能造成了嚴重影響。
        ORM的數據緩存應包含如下幾個層次:
    1、事務級緩存:事務級緩存是基于Session生命周期實現的,每個Session會在內部維持一個數據緩存,此緩存隨著Session的創建而存在,因此也成為Session Level Cache(內部緩存)
    2、應用級/進程級緩存:在某個應用中,或者應用中某個獨立數據訪問子集中的共享緩存。此緩存可由多個事物共享。在Hibernate中,應用級緩存在SessinFactory層實現,所有由此SessionFactory創建的Session實例共享此緩存。多實例并發運行的環境要特別小心進程級緩存的調用。
    3、分布式緩存:分布式緩存由多個應用級緩存實例組成集群,通過某種遠程機制實現各個緩存實例間的數據同步,任何一個實例的數據修改操作,將導致整個集群間的數據狀態同步。由于多個實例間的數據同步機制,每個緩存實例發生的變動都會復制到其余所有節點中,這樣的遠程同步開銷不可忽視。

        Hibernate數據緩存分為2個層次,1、內部緩存2、二級緩存hibernate中,緩存將在以下情況中發揮作用:
    1、通過ID加載數據時
    這包括了根據id查詢數據的Session.load方法,以及Session.ierate等批量查詢方法
    2、延遲加載

        Session在進行數據查詢操作時,會首先在自身內部的一級緩存中進行查找,如果一級緩存未能命中,則將在二級緩存中查詢,如果二級緩存命中,則以此數據作為結果返回。
        如果數據滿足以下條件,則可將其納入緩存管理
    1、數據不會被第三方應用修改
    2、數據大小在可接受的范圍之內
    3、數據更新頻率較低
    4、同一數據可能會被系統頻繁引用
    5、非關鍵數據(關鍵數據,如金融賬戶數據)
    Hibernate本身并未提供二級緩存的產品化實現(只是提供了一個基于Hashtable的簡單緩存以供調試),而是為眾多的第三方緩存組件提供了接入接口,我們可以根據實際情況選擇不同的緩存實現版本。

       
    posted @ 2009-12-22 15:01 王永慶 閱讀(219) | 評論 (0)編輯 收藏
        比較字符串是否相等使用equals方法
        使用"=="與equals到底有哪些不同?
        equals:可以比較內容,是2個字符串內容的比較。
        ==:數值比較,比較的是內存地址的值是否相等。

        一個字符串就是String類的匿名對象。
        String name1 = new String("wyq");->開辟了2個空間,其中一個是垃圾空間。
        String name2 = "wyq";->開辟了一個空間,所以應該選擇它。

        String的另一個特殊之處:String使用了Java中的共享模式,它只要發現在內存中有這塊數據,不會在內存中重新生成。
        String類中的內容一旦聲明則不可改變。
        StringBuffer與String的本質區別,在于StringBuffer可以改變。

        this可以調用本類中的屬性,也可以調用本類中的方法(含構造方法this())。
        注意:構造方法本身必須在首行被使用,為了給類中的屬性初始化。
        this調用屬性、本類方法、構造方法這三點是this的基本應用,也是最常用的,但是以上三點實際上可以綜合成一點---表示當前對象。
        this表示當前對象主要應用在一點:用于進行對象的比較。
    public boolean compare(Person p1){
        
    boolean flag = false;
        Person p2 
    = this;
        
    if(p1.name.equals(p2.name)&&p1.age==p2.age)
        
    {
           flag 
    = true;
        }

        
    return flag;
    }

    posted @ 2009-12-08 09:56 王永慶 閱讀(191) | 評論 (0)編輯 收藏

        在軟件中,要么全有要么全無的操作成為事務。事務允許你把幾個操作組成一個單一的工作單元,這個工作單元要么全部發生要么全部不發生。如果每件事都順利,那么這個事務是成功的。但是如果任何一件事情出錯的話,那么已經發生的行為就被清除掉,就像什么事情都沒發生一樣。
        Spring對事務管理有豐富的支持,程序控制的和聲明式的。
        原子性(Atomic):事務由一個或多個行為綁定在一起組成,好像是一個單獨工作單元。原子性確保在十五中的所有操作要么都發生,要么都不發生。
        一致性(Consistent):一旦一個事務結束了(不管成功失敗),系統所處的狀態和它的業務規則是一致的。就是說數據應當不會被破壞。
        隔離性(Isolated):事務應該允許多個用戶操作同一數據,一個用戶的操作不會和其他用戶的操作相混淆。因此,事務必須是互相隔離的,防止并發讀寫同一數據的情況發生。
        持久性(Durable):一旦事務完成,事務的結果應該持久化,這樣不管什么樣的系統崩潰,他們都將幸免于難。
     
        Spring對程序控制事務管理的支持和EJB的有很大不同。EJB的事務管理和JTA密不可分,和EJB不同的是,Spring使用了一種回調機制,把真實的事務實現從事務代碼中抽象出來。選擇程序控制事務管理還是聲明式事務管理,很大程度上是在細粒度控制與簡便操作之間做出決定。當你在代碼中編寫事務時,你能精確控制事務的邊界,在你希望的地方精確的開始和結束。典型的情況下,你不需要程序控制事務所提供的細粒度控制,你會選擇在上下文定義文件中聲明你的事務。

        Spring對聲明式事務管理的支持是通過它的AOP框架實現的。這樣做是非常自然的,因為事務是系統級的,凌駕于應用的主要功能之上的。

        在Spring里,事務屬性是對事務策略如何應用到方法的描述。這個描述包括:傳播行為、隔離級別、只讀提示、事務超時間隔
        傳播行為:
        PROPAGATION_MANDATORY:表示該方法必須運行在一個事務中。如果當前事務不存在,將拋出一個異常。
        PROPAGATION_NESTED:表示如果當前已經存在一個事務,則該方法應當運行在一個嵌套的事務中。被嵌套的事務可以從當前事務中單獨的提交或回滾。如果當前事務不存在,那么它看起來和PROPAGATION_REQUIRED沒有兩樣。
        PROPAGATION_NEVER:表示當前的方法不應該運行在一個事務上下文中。如果當前存在一個事務,則會拋出一個異常。
        PROPAGATION_NOT_SUPPORTED:表示該方法不應在事務中運行。如果一個現有的事務正在運行中,它將在該方法的運行期間被掛起。
        PROPAGATION_REQUIRED:表示當前方法必須運行在一個事務中。如果一個現有的事務正在運行中,該方法將運行在這個事務中。否則的話,要開始一個新的事務。
        PROPAGATION_REQUIRES_NEW:表示當前方法必須運行在它自己的事務里。它將啟動一個新的事務。如果有事務運行的話,將在這個方法運行期間被掛起。
        PROPAGATION_SUPPORTS:表示當前方法不需要事務處理環境,但如果有一個事務已經在運行的話,這個方法也可以在這個事務里運行。

       傳播規則回答了一個問題:就是新的事務是否要被啟動或是被掛起,或者方法是否要在事務環境中運行。

       隔離級別:在一個典型的應用中,多個事務并發運行,經常會操作同一個數據來完成它們的任務。并發,雖然是必須的,但會導致下面問題:
    1、臟讀:臟讀發生在一個事務讀取了被另一個事務改寫但還未提交的數據時。如果這些改變在稍后被回滾,那么第一個事務讀取的數據就是無效的。
    2、不可重復讀:不可重復讀發生在一個事務執行相同的查詢2次或2次以上,但每一次查詢結果都不同時。這通常是由于另一個并發事務在2次查詢之間更新了數據。
    3、幻讀:幻讀和不可重復讀相似。當一個事務讀取幾行紀錄后,另一個并發事務插入一些記錄,幻讀就發生了。隔離級別有如下幾個:
    ISOLATION_DEFAULT:使用后端數據庫默認的隔離級別
    ISOLATION_READ_UNCOMMITTED:允許你讀取還未提交的改變了的數據,可能導致臟讀、幻讀、不可重復讀
    ISOLATION_READ_COMMITTED:允許在并發事務已經提交后讀取。可防止臟讀,但幻讀和不可重復讀仍可能發生。
    ISOLATION_REPEATABLE_READ:對相同字段的多次讀取的結果是一致的,除非數據被事務本身改變。可防止臟讀和不可重復讀,但幻讀仍可能發生。
    ISOLATION_SERIALIZABLE:完全服從ACID的隔離級別,確保不發生臟讀、不可重復讀和幻讀。這在所有隔離級別中也是最慢的。

        只讀:如果一個事務只對后端是據庫執行讀操作,數據庫就可能利用事務只讀的特性,使用某些優化措施。通過聲明一個事務為只讀,你就給了后端數據庫一個機會,來應用那些它認為合適的優化措施。因為只讀的優化措施是在事務啟動時由后端數據庫實施的,所以,只有將那些具有可能啟動新事務的傳播行為的方法的事務標記成只讀才有意義(PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW和PROPAGATION_NESTED) TransactionProxyFactoryBean參照一個方法的事務屬性,決定如何在那個方法上執行事務策略。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans
        
    xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation
    ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
        
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
            
    <property name="jndiName">
                
    <value>java:comp/env/jdbc/myDatasource</value>
            
    </property>
        
    </bean>
        
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            
    <property name="dataSource">
                
    <ref bean="dataSource"/>
            
    </property>
        
    </bean>
        
    <!-- 這個對象有一個值為courseService的id.當應用從應用上下文里請求一個courseService時,它將得到一個被
        TransactionProxyFactoryBean包裹的實例。 
    -->
        
    <bean id="courseService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
            
    <!-- 代理所實現的接口 -->
            
    <property name="proxyInterfaces">
                
    <list>
                    
    <value>
                        com.springinaction.training.service.CourseService
                    
    </value>
                
    </list>
            
    </property>
            
    <!-- 被代理的對象 -->
            
    <property name="target">
                
    <ref bean="courseServiceTarget"/>
            
    </property>
            
    <!-- 事務管理器 -->
            
    <property name="transactionManager">
                
    <ref bean="transactionManager"/>
            
    </property>
            
    <!-- 事務的屬性源 -->
            
    <property name="transactionAttributeSource">
                
    <ref bean="transactionAttributeSource"/>
            
    </property>
        
    </bean>
        
    <!-- 要知道盡管可以改變MatchAlwaysTransactionAttributeSource的事務屬性參數,但它總是返回相同的事務屬性,而
        不關心參與交易的哪一個方法。當你有一個相對簡單的應用,把同樣的事務策略應用到所有方法都沒問題時,使用MatchAlwaysT
        ransactionAttributeSource就相當好。但是,在那些更為復雜的應用中,你很可能需要對不同的方法應用不同的事務策略。在那樣
        情況下,你需要在應用何種策略的問題上做更多精確的控制。 
    -->
        
    <bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
            
    <property name="transactionAttribute">
                
    <ref bean="myTransactionAttribute"/>
            
    </property>
        
    </bean>
        
    <!-- 定義事務策略 -->
        
    <bean id="myTransactionAttribute" class="org.springframework.transaction.interceptor.DefaultTransactionAttribute">
            
    <!-- 傳播行為 -->
            
    <property name="propagationBehaviorName">
                
    <value>PROPAGATION_REQUIRES_NEW</value>
            
    </property>
            
    <!-- 隔離級別 -->
            
    <property name="isolationLevelName">
                
    <value>ISOLATION_REPEATABLE_READ</value>
            
    </property>
        
    </bean>
    </beans>

     

    除了將transactionAttributeSource對象織入到TransactionProxyFactoryBean的transactionAttributeSource屬性中外,還有一種簡單的方法。發展到現在,TransactionProxyFactoryBean也有一個transactionAttributes屬性為transactionProperties.

    <?xml version="1.0" encoding="UTF-8"?>
    <beans
        
    xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation
    ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
        
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
            
    <property name="jndiName">
                
    <value>java:comp/env/jdbc/myDatasource</value>
            
    </property>
        
    </bean>
        
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            
    <property name="dataSource">
                
    <ref bean="dataSource"/>
            
    </property>
        
    </bean>
        
    <!-- 這個對象有一個值為courseService的id.當應用從應用上下文里請求一個courseService時,它將得到一個被
        TransactionProxyFactoryBean包裹的實例。 
    -->
        
    <bean id="courseService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
            
    <!-- 代理所實現的接口 -->
            
    <property name="proxyInterfaces">
                
    <list>
                    
    <value>
                        com.springinaction.training.service.CourseService
                    
    </value>
                
    </list>
            
    </property>
            
    <!-- 被代理的對象 -->
            
    <property name="target">
                
    <ref bean="courseServiceTarget"/>
            
    </property>
            
    <!-- 事務管理器 -->
            
    <property name="transactionManager">
                
    <ref bean="transactionManager"/>
            
    </property>
            
    <!-- 事務的屬性源 -->
            
    <property name="transactionAttributeSource">
                
    <ref bean="transactionAttributeSource"/>
            
    </property>
        
    </bean>
        
    <!-- NameMatchTransactionAttributeSource的properties屬性把方法名映射到事務屬性描述器上。注意CourseException
        用一個負號標記。異常可以用負號或正號標記,當負號異常拋出時,將觸發回滾;相反的,正號異常表示事務仍可提交,即使這個異常拋出 
    -->
        
    <bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
            
    <property name="properties">
                
    <props>
                    
    <prop key="enrollStudentInCourse">
                        PROPAGATION_REQUIRES_NEW,ISOLATION_REPEATABLE_READ,readOnly,
                        -CourseException
                    
    </prop>
                    
    <!-- 還可以使用通配符 -->
                    
    <prop key="get*">
                        PROPAGATION_SUPPORTS
                    
    </prop>
                
    </props>
            
    </property>
        
    </bean>
    </beans>

     

     

    posted @ 2009-11-22 11:43 王永慶 閱讀(257) | 評論 (0)編輯 收藏

        HQL作為Hibernate的查詢語言,提供了ANSI SQL面向對象的封裝形式。
        與Criteria和HQL互為補充,Hibernate也提供了對原生SQL以及存儲過程的支持,相對于JDBC的SQL操作,Hibernate提供了更為妥善的封裝。代碼如下:

    package com.testproject.hibernate;

    import java.util.Iterator;
    import java.util.List;

    import org.hibernate.Query;
    import org.hibernate.Session;

    public class HibernateSqlQuery {
        Session session 
    = null;
        
    public void querySql(){
            String sql 
    = "select {usr.*} from T_User usr";
            List list 
    = session.createSQLQuery(sql).addEntity("usr", TUser.class).list();
            Iterator it 
    = list.iterator();
            
    while(it.hasNext()){
                TUser user 
    = (TUser)it.next();
            }

        }

        
    public void queryMappingSql(){
            Query query 
    = session.getNamedQuery("queryUser");
            query.setParameter(
    "name","Erica");
            Iterator it 
    = query.list().iterator();
            
    while(it.hasNext()){
                TUser user 
    = (TUser)it.next();
            }

        }

    }

     

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
    >
    <hibernate-mapping>
        
    <class name="com.testproject.hibernate.TUser" table="T_USER">
            
    <id name="id" column="id">
                
    <generator class="native"></generator>
            
    </id>
        
    </class>
        
    <sql-query name="queryUser">
            
    <![CDATA[
                select {usr.*} from T_User usr where name=:name
            
    ]]>
            
    <return alias = "usr" class="com.testproject.hibernate.TUser"></return>
        
    </sql-query>
        
    <!-- 基于存儲過程查詢 sql-query節點的callable屬性設定為true,指明當前查詢基于存儲過程定義-->
        
    <sql-query name="getUsersByAge" callable="true">
            
    <return alias="user" class="com.testproject.hibernate.TUser">
                
    <return-property name="id" column="ID"></return-property>
                
    <return-property name="name" column="NAME"></return-property>
                
    <return-property name="age" column="AGE"></return-property>
            
    </return>
            {?=call getUsersByAge(?)}
        
    </sql-query>
    </hibernate-mapping>






        與HQL相同,Native SQL也可以在實體映射文件中進行配置:

    posted @ 2009-11-21 21:37 王永慶 閱讀(241) | 評論 (0)編輯 收藏
         摘要:     實體Bean包含BMP和CMP兩種類型。對BMP實體Bean而言,開發者必須提供各自的數據訪問邏輯。為了實現BMP,通常會使用操作數據庫的API,比如JDBC.對于CMP實體Bean而言,EJB容器會自動實現數據訪問邏輯。這就是CMP的優勢所在。通常,只有在應用服務器提供的CMP和目標RDBMS不能滿足性能要求時,才去考慮BMP.此時,開發者能夠細粒度調整BM...  閱讀全文
    posted @ 2009-11-21 12:32 王永慶 閱讀(214) | 評論 (0)編輯 收藏

        Criteria提供了符合面向對象編程風格的查詢封裝模式。不過HQL提供了更加豐富靈活的特性,它在涵蓋了Criteria功能范圍的前提下,提供了更為強大的查詢能力。HQL基于SQL,同時提供了更加面向對象的封裝。
        實體查詢:HQL子句本身大小寫無關,但是其中出現的類名和屬性名必須注意大小寫區分。需要注意的是,Hibernate中,查詢的目標實體存在著繼承關系的判定,如"from TUser"將返回所有TUser以及TUser子類的記錄,我們知道,Java中所有類的根類都是java.lang.Object,那么,如下HQL將返回數據庫中所有庫表的記錄:"from java.lang.Object",在where子句中,我們可以通過比較操作符指定條件,=,<>,>,>,<=,>=,between,notbetween,in,not in,is,like等。與SQL相同,我們可以通過and,or等邏輯連接符組合各個邏輯表達式。

        屬性查詢:有時我們并不需要獲取完整的實體對象,只需要現實部分列,通過HQL也可以做到這點,如:"select user.name,user.age form TUser user"表明我們需要讀取name和age屬性的內容,而此時,返回的list數據結構中,每個條目都是一個對象數組(Object[]),其中一次包含了我們所獲取的屬性數據。
        如果覺得返回數組的方式不夠符合面向對象的風格,我們可以通過在HQL中動態構造對象實例的方法對這些平面化的數據進行封裝。"select new TUser(user.name,user.age) from TUser user",我們通過HQL獲取數據的部分屬性值,與此同時,我們也可以在HQL的select字句中使用統計函數,甚至原生SQL函數,或者利用distinct關鍵字,剔除返回集中的重復記錄。

        實體更新與刪除:在Hibernate2中,HQL僅僅用于數據查詢,而在Hibernate3中,HQL具備了更加強大的功能。實體更新與刪除就是其中的主要特征之一。

        分組和排序:與SQL類似,HQL通過order by子句實現對查詢結果的排序,order by子句可以指定多個排序條件:"from TUser user order by user.name ,user.age desc"通過Group by子句可進行分組統計。如:"select count(user),user.age from TUser user group by user.age",我們知道where子句可以對記錄進行甄選。那么,對于Group by子句獲得的結果集我們可以通過Having子句進行甄選。例如:"select count(user),user.age from TUser user gourp by user.age having count(user)>10".

         參數綁定:類似JDBC中的SQL操作,我們可以通過順序占位符"?"對參數進行標識,并在之后對參數內容進行填充。建議使用Query接口"from TUser user where user.name=? and user.age>?",這里除了順序占位符,我們還可以使用引用占位符,如:"from TUser where name=:name"參數綁定機制可以使得查詢語法與具體參數數值相互獨立。這樣,對于參數不同,查詢語法相同的查詢操作,數據庫即可實施性能優化策略。同時,參數綁定機制也杜絕了參數值對查詢語法本身的影響。

         引用查詢:SQL語句混雜在代碼之間將破壞代碼的可讀性,并使得系統的可維護性降低。為了避免這樣的情況出現,我們通常采取將SQL配置化的方式,也就是將SQL保存在配置文件中,需要調用的時候在進行讀取。
    <query name="queryByName">
     <![CDATA[
      from TUser user where user.name=:name
     ]]>
    </query>
    之后,我們可通過session.getNamedQuery方法從配置文件中調用引用的HQL.

         聯合查詢:inner join,left outer join,right outer join,full join
         子查詢:如:"from TUser user where (select count(*) from user.addresses)>1"HQL中,子查詢必須出現在where子句中,且必須以一對圓括號包圍。
         數據加載方式:Hibernate支持以下幾種數據加載方式:
    1、即時加載:當實體加載完畢后,立即加載其關聯數據。
    2、延遲加載:實體加載時,其關聯數據并非即刻獲取,而是當關聯數據第一次被訪問時再進行讀取。
    3、預先加載:預先加載時,實體及其關聯對象同時讀取,這與即時加載類似。
    4、批量加載:對于即時加載和延遲加載,可以采用批量加載方式進行性能上的優化。

    posted @ 2009-11-15 22:25 王永慶 閱讀(319) | 評論 (0)編輯 收藏

    持久化實體Bean的兩種方式:
        既然需要將實體Bean映射到存儲源中,應用肯定需要提供操作RDBMS的代碼。
        Bean管理持久化實體Bean,是手工完成持久化行為的EJB類型。換句話所,組件開發者必須開發代碼,以將內存中的持久化域存儲到底層存儲源中。這種方式成為BMP。
        EJB規范還提供了BMP的替代組件類型:借助于EJB容器完成數據的持久化。這就是容器管理持久化(CMP)。此時,通常都要將持久化邏輯從CMP中剝離出來。然后借助于容器提供的工具完成數據的自動持久化。最后,EJB容器將生成訪問數據庫的代碼。注意,CMP是獨立于任何O/RMapping技術的數據對象,因此可以在各種企業環境中重用CMP組件。
        CMP極大減少了實體Bean的代碼量,因為不用直接編寫JDBC代碼了。EJB容器將會處理所有的持久化操作,這是EJB勢能應用的優勢之一。
        在執行ejbCreate()方法期間,即在初始化內存中的實體Bean時,將會在底層RDBMS中插入新的記錄,并將這些記錄同實體Bean實例建立起映射關系。當調用BMP實體Bean的ejbCreate()時,它將負責生成RDBMS中的數據。類似的,當調用BMP實體Bean的ejbRemo()時,它將負責RDBMS中數據的刪除。

        在EJB領域中,客戶并沒有直接調用EJB實例,它們僅僅調用了EJB對象代理。借助于Home對象能夠生成EJB對象。因此,對于定義在EJB Bean類中的各個ejbCreate()方法,在Home接口中也將存在對象的create()方法。當客戶調用Home對象的create()方法時,容器將把調用請求委派給ejbCreate()方法。
        開發者可以通過多種方式查找實體Bean.需要在實體Bean的Home接口中列舉出這些查找方法。我們稱這些方法為"finder"方法。除了暴露創建、銷毀實體Bean實例的方法外,Home接口還需暴露finder方法。這是實體Bean的Home接口同其他EJB類型中的Home接口的最明顯區別。

        實體上下文,所有的EJB組件都存在上下文對象供組件訪問到容器環境使用。這些上下文對象含有EJB容器設置的環境信息。因此EJB組件能夠訪問到上下文,從而獲取各種信息,比如事務,安全性信息。對于實體Bean而言,存在javax.ejb.EntityContext上下文接口。它繼承自EJBContext
    public interface javax.ejb.EntityContext extends javax.ejb.EJBContext{
     public javax.ejb.EJBLocalObject getEJBLocalObject();
     public javax.ejb.EJBObject getEJBObject();
     public java.lang.Object getPrimarykey();
    }
        通過調用getEJBObject()方法,當前客戶能夠獲得某實體Bean實例對應的EJB對象。客戶調用的是EJB對象,而不是實體Bean實例本身。因此,客戶能夠在應用中引用返回的EJB對象。
        實體Bean實例對應的主鍵可以通過getPrimaryKey()方法獲得。主鍵唯一標識某實體Bean實例。當實體Bean實例存儲到存儲源中時,可以使用主鍵獲得單個實體Bean實例。由于在RDBMS中也存在主鍵,因此主鍵能夠唯一標識某個實體Bean實例。

    posted @ 2009-11-15 12:21 王永慶 閱讀(199) | 評論 (0)編輯 收藏

        實體Bean是持久化對象,它能夠存儲到持久化存儲源中。實體Bean是EJB編程模型中最為重要的利器之一。
        將對象映射到RDBMS的技術稱之為對象-關系映射。它能夠實現內存對象同關系數據的相互轉換。O/R映射器能夠將Java對象映射到任意RDBMS模式。比如簡單的O/RMapping引擎能夠將Java類映射成SQL表定義。Java語言提供的對象序列化功能比O/RMapping簡單多了。O/RMapping是更加復雜、成熟的對象持久化機制。通過將Java對象分解成關系數據,應用便能夠查找到所需的數據了。
        通過如下兩種方式能夠完成Java對象到關系數據的映射。其一,通過硬編碼實現O/RMapping.其二,借助于O/RMapping產品,自動完成映射過程,比如:Hibernate.
        對于任何成熟的、基于OO多層部署的企業應用而言,總可以劃分出2種截然不同的組件類型。1、應用邏輯組件,2、持久化數據組件。會話Bean和實體Bean的最大區別在于實體Bean是實體,客戶是可以看的到的。因此實體Bean能夠獨立于客戶應用的生命周期。對于實體Bean而言,通過比較它們各自含有的數據便能夠區分不同的實體Bean.這意味著客戶能夠引用單個的實體Bean實例并將它傳入到其他應用中,不同的客戶可以共享同樣的實體Bean實例,這對于會話Bean是辦不到的。會話Bean建模過程或者工作流。實體Bean本身就是客戶,它就是持久化狀態對象。
        實體Bean實例存在幾方面的含義:
    1、持久化數據的Java表示,即它能夠從持久化存儲源裝載數據到內存中。同時,實體Bean實例能夠將裝載到的數據存儲到實例的成員變量中。
    2、通過修改內存中的Java對象可以改變數據的取值。
    3、還可以將修改后的數據保存到存儲源匯中,從而更新RDBMS中的物理數據。
        實體Bean是持久化對象,它能夠長期存在。即使出現了不可恢復的失敗,比如應用服務器癱瘓、數據庫癱瘓,實體Bean還是能夠存活的。原因在于實體Bean只是對底層具有容錯行為的持久化存儲源中數據的映射,因此,即使極其癱瘓,內存中的實體Bean實例還可以重新構建。在極其重啟后,實體Bean實例需要從底層存儲源裝載數據,并使用獲得的數據對實體Bean實例中的各個域進行setter操作。實體Bean比客戶會話的生命周期要長。可以認為,數據庫中記錄存活的時間決定了實體Bean實例的生命周期。
        相同數據往往存在多分物理拷貝,比如內存中的實體Bean實例、實體Bean數據本身,他們都是對RDBMS中數據的拷貝。因此,EJB容器需要提供某種機制實現數據在Java對象和RDBMS間的自動傳輸。實體Bean的Bean類為此提供了2個特殊方法:
    ejbLoad():它能夠從持久化存儲源中讀取數據,并存儲到實體Bean實例的域中。
    ejbStore():它能夠將當前實體Bean實例的域值保存到底層RDBMS中。
    那么何時需要完成內存中實體Bean實例和RDBMS中數據的傳遞和轉換,開發者需要知道是誰調用了ejbLoad()和ejbStore(),答案是EJB容器。它們是回調方法,供EJB容器調用。EJB規范要求所有的實體Bean組件必須提供它們。至于讀取或存儲數據的時機,由EJB容器決定。依據實體Bean實例當前的事務狀態,EJB容器會自動計算出需要調用實體Bean實例中的ejbLoad(),ejbStore()方法的時機,這也是使用實體Bean組件的優勢之一:開發者不用考慮java對象同步底層RDBMS的問題。

        為了滿足大量并發客戶訪問同一數據的要求,架構師需要借助于實體Bean設計出高性能的訪問系統。如下給出一種解決方案:允許多個客戶共享同一實體Bean實例。因此,實體Bean實例能夠同時服務多個客戶。盡管表面上看是可行的,但是對于EJB而言,這是行不通的。原因有亮點:其一,為實現實體Bean實例服務多個并發客戶,必須保證實體Bean實例是線程安全的,開發線程安全的代碼并不是一件容易的工作,而且經常會出現一堆錯我。其二,底層事務系統幾乎不可能控制多個線程的并發執行,事務往往同具體的線程綁定在一起。因此,基于上述理由,單個實體Bean實例只能夠在單線程環境中運行。對于所有的EJB組件而言,包括會話Bean、消息驅動Bean、實體Bean,它們都是以單線程方式運行的。
        當然,強制要求各個實體Bean實例只能同時服務單個客戶,將引入性能瓶頸。由于實例以單線程方式運行,客戶需要排隊等候實體Bean實例,從而獲得對實體Bean實例的調用,這對于大型企業應用而言,是不允許出現的
        為了提供系統性能,EJB容器會實例化同一實體Bean的多個實例。這使得多個客戶能夠并發同不同實體Bean實例進行交互,而這些實體Bean實例代表了同一RDBMS數據。事實上,這就是EJB容器的運行行為。因此,客戶再也不用排隊等候實體Bean實例,因為存在多個實體Bean實例了。
        一旦多個實體Bean實例代表了同一RDBMS數據,則引入了另外一個問題:數據癱瘓。如果多個實體Bean實例代表的數據是通過緩存管理的,則需要在內存中拷貝多分緩存中的數據。顯然,某些緩存中的數據將變得陳舊,因此會出現很多過期的數據。
        為了實現實體Bean實例的緩存一致性,各個實體Bean實例必須同底層存儲元進行同步。EJB容器將通過調用ejbLoad(),ejbStore()方法同步這些實體Bean實例。
        至于實體Bean實例同底層RDBMS數據的同步頻率,則取決于事務。事務將各個客戶請求隔離起來。借助于事務實現數據同步。

        EJB容器提供的實例池是很有意義的。當然,并不是只有實體Bean才存在實例池。在將實體Bean實例重新分配給不同EJB對象時,會存在一些問題,并要求容器去解決。比如當實體Bean實例被指定給EJB對象時,它可能還持有資源(比如Socket連接)。如果將實體Bean實例放置在實例池中,Socket連接不在需要。因此為實現資源的獲取和釋放,實體Bean的Bean類需要實現如下2個回調方法:
    1、ejbActivate().在將實體Bean實例從實例池中取出來時,EJB容器會自動調用它。該過程稱之為激活。進而,EJB容器會將實體Bean實例分配給某EJB對象,并同時獲得主鍵對象。在執行ejbActivate()方法期間,實例需要獲得所需的資源,比如Socke,否則,在將實體Bean實例分配給某EJB對象時,無法對資源進行操作。
    2、ejbPassivate().在將實體Bean實例放置到實例池中時,EJB容器會調用它。注意,它也是回調方法。這一過程稱之為掛起。進而,EJB容器需要從某EJB對象中取回分配于它的實體Bean實例,并將實例的主鍵對象也收回。在執行ejbPassivate()方法期間,需要釋放ejbActivate()執行期間獲得的相關資源,比如:Socket.
        一旦實體Bean實例被掛起,不但要釋放它持有的資源,還將實例的狀態信息保存起來。因此,實體Bean實例最新的狀態信息可以從RDBMS中找到了。為了保存實體Bean實例的域信息到RDBMS中,容器要在掛起實例前調用ejbStore()方法。類似的,一旦實體Bean被激活,不但要獲得所需的資源,還要從RDBMS裝載最新的數據,為了完成數據的讀取,EJB容器將在激活實體Bean實例后調用ejbLoad()方法。


     

    posted @ 2009-11-15 11:46 王永慶 閱讀(291) | 評論 (0)編輯 收藏
    僅列出標題  下一頁
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(1)

    隨筆分類

    隨筆檔案

    關注blogs

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产免费人成视频尤勿视频| 国产成人综合亚洲绿色| 亚洲人成免费网站| 亚洲精品国产肉丝袜久久| 18以下岁毛片在免费播放| 亚洲无砖砖区免费| 免费无码黄十八禁网站在线观看| 亚洲最大黄色网址| 午夜一级毛片免费视频| 老牛精品亚洲成av人片| 国产偷窥女洗浴在线观看亚洲| 一级毛片免费播放视频| 亚洲乱码中文字幕久久孕妇黑人| 成全视频在线观看免费| 久久亚洲精品国产精品| 亚洲乱妇老熟女爽到高潮的片 | 亚洲精品乱码久久久久66| 青青草国产免费国产是公开| 亚洲精品亚洲人成在线观看下载| 一区二区视频在线免费观看| 亚洲成av人片在线观看无码不卡| 99久久免费观看| 亚洲午夜一区二区电影院| 青草草在线视频永久免费| 五月婷婷免费视频| 在线电影你懂的亚洲| 日本特黄特色aa大片免费| 一级全免费视频播放| 亚洲精品永久www忘忧草| 成在线人永久免费视频播放| 成人毛片100免费观看| 亚洲国产精品张柏芝在线观看| 免费看国产曰批40分钟| 美女视频黄的免费视频网页 | 亚洲成人免费在线观看| 久久午夜无码免费| 国产成人精品日本亚洲专| 国产一精品一aⅴ一免费| 日本黄色动图免费在线观看| 亚洲综合欧美色五月俺也去 | 久久久久亚洲av成人无码电影|