隨筆:93 文章:11 評論:22 引用:0
          首頁 發(fā)新隨筆
          發(fā)新文章 聯(lián)系 聚合管理

          在Oracle中,要按特定條件查詢前N條記錄,用個rownum就搞定了。
          select * from emp where rownum <= 5
          結(jié)果只查詢5條記錄, oracle會自動展現(xiàn)一個rownum的屬性表示記錄排序號

          而select * from emp where rownum > 5 ;則是失敗的。
          因為:rownum是oracle預(yù)處理字段,默認(rèn)標(biāo)序是1,只有記錄集已經(jīng)滿足條件后才會進(jìn)行后續(xù)編號。由于第一條記錄rownum默認(rèn)是1,而你的條件是rownum>=6 對第一條記錄比較它的rownum肯定不大于6 所以不滿足條件 oracle舍棄第一條記錄將數(shù)據(jù)庫第二條記錄標(biāo)序為1再進(jìn)行比較  肯定都不滿足rownum>=6  這樣循環(huán)也就是說由于沒有記錄滿足rownum>=6所以記錄一直被舍棄,rownum一直是1 。

          解決方案: 利用查詢時,自動生成的rownum屬性.
          排序方法:
            select * from (
                 select a1.*, rownum rwn  from emp a1   where rownum <=10
              ) where rwn >= 6;
            或者
            select * from (
              select qx.*,row_number() over(order by qx.empno) rwn from emp qx
            ) where rwn between 6 and 10
          -------------------------------------------------------------------------
          使用注意:

          1排序?qū)е聰?shù)據(jù)重復(fù):


          table1中表有字段(其余字段省)
          ID  主鍵
          DATA_UPDATE_TIME 數(shù)據(jù)更新時間(只存儲了年月日)

          分頁查詢的語句如下
          select *
             from (
                  select row_.*, rownum rownum_
                     from ( select  p.id from table1 p
                       order by  p.DATA_UPDATE_TIME desc )
             row_ where rownum <= )
          where rownum_ >

          以每頁顯示10條為例
          第一次  rownum <= 10)   where rownum_ > 0
          第二次  rownum <= 20)   where rownum_ > 10

          發(fā)現(xiàn)有一條記錄在兩次查詢結(jié)果中重復(fù)出現(xiàn),不知道問題出在哪里,請忙幫看看。

          另:
          DATA_UPDATE_TIME 的值有重復(fù),不知道跟它有沒有關(guān)系。
          如果按ID排的話就不會出現(xiàn)這個問題


          解答:
          如果order by 不能唯一確定記錄的順序就會出現(xiàn)這個問題。
          解決的方法是把分頁部分全部拿到最外層進(jìn)行。

          Java代碼 復(fù)制代碼 收藏代碼
          1. select * from (    
          2.   select row_.*, rownum rownum_    
          3.   from (   
          4.     select p.id from table1 p    
          5.     order by p.DATA_UPDATE_TIME desc    
          6.   ) row_   
          7. )    
          8. where rownum_ > ? and rownum_ <= ?   

          2 排序的id順序:
          Oracle中的rownum的是在取數(shù)據(jù)的時候產(chǎn)生的序號,所以想對指定排序的數(shù)據(jù)去指定的rowmun行數(shù)據(jù)就必須注意了。
          SQL> select rownum ,id,name from student order by name;
              ROWNUM ID     NAME
          ---------- ------ ---------------------------------------------------
                   3 200003 李三
                   2 200002 王二
                   1 200001 張一
                   4 200004 趙四
          可以看出,rownum并不是按照name列來生成的序號。系統(tǒng)是按照記錄插入時的順序給記錄排的號,rowid也是順序分配的。為了解決這個問題,必須使用子查詢
          SQL> select rownum ,id,name from (select * from student order by name);
              ROWNUM ID     NAME
          ---------- ------ ---------------------------------------------------
                   1 200003 李三
                   2 200002 王二
                   3 200001 張一
                   4 200004 趙四
          這樣就成了按name排序,并且用rownum標(biāo)出正確序號(有小到大)


          ------------
          參考Oracle的rownum原理和使用  http://tenn.iteye.com/blog/99339

          在Oracle中,要按特定條件查詢前N條記錄,用個rownum就搞定了。
          select * from emp where rownum <= 5
          而且書上也告誡,不能對rownum用">",這也就意味著,如果你想用
          select * from emp where rownum > 5
          則是失敗的。要知道為什么會失敗,則需要了解rownum背后的機制:
          1 Oracle executes your query.

          2 Oracle fetches the first row and calls it row number 1.

          3 Have we gotten past row number meets the criteria? If no, then Oracle discards the row, If yes, then Oracle return the row.

          4 Oracle fetches the next row and advances the row number (to 2, and then to 3, and then to 4, and so forth).

          5 Go to step 3.

          了解了原理,就知道rownum>不會成功,因為在第三步的時候查詢出的行已經(jīng)被丟棄,第四步查出來的rownum仍然是1,這樣永遠(yuǎn)也不會成功。

          同樣道理,rownum如果單獨用=,也只有在rownum=1時才有用。

           

          對于rownum來說它是oracle系統(tǒng)順序分配為從查詢返回的行的編號,返回的第一行分配的是1,第二行是2,依此類推,這個偽字段可以用于限制查詢返回的總行數(shù),而且rownum不能以任何表的名稱作為前綴。
           舉例說明:
          例如表:student(學(xué)生)表,表結(jié)構(gòu)為:
          ID       char(6)      --學(xué)號
          name    VARCHAR2(10)   --姓名
          create table student (ID char(6), name VARCHAR2(100));
          insert into sale values('200001',‘張一’);
          insert into sale values('200002',‘王二’);
          insert into sale values('200003',‘李三’);
          insert into sale values('200004',‘趙四’);
          commit;
          (1) rownum 對于等于某值的查詢條件
          如果希望找到學(xué)生表中第一條學(xué)生的信息,可以使用rownum=1作為條件。但是想找到學(xué)生表中第二條學(xué)生的信息,使用rownum=2結(jié)果查不到數(shù)據(jù)。因為rownum都是從1開始,但是1以上的自然數(shù)在rownum做等于判斷是時認(rèn)為都是false條件,所以無法查到rownum = n(n>1的自然數(shù))。
          SQL> select rownum,id,name from student where rownum=1;(可以用在限制返回記錄條數(shù)的地方,保證不出錯,如:隱式游標(biāo))
          SQL> select rownum,id,name from student where rownum=1;
              ROWNUM ID     NAME
          ---------- ------ ---------------------------------------------------
                   1 200001 張一
          SQL> select rownum,id,name from student where rownum =2;
              ROWNUM ID     NAME
          ---------- ------ ---------------------------------------------------
          (2)rownum對于大于某值的查詢條件
             如果想找到從第二行記錄以后的記錄,當(dāng)使用rownum>2是查不出記錄的,原因是由于rownum是一個總是從1開始的偽列,Oracle 認(rèn)為rownum> n(n>1的自然數(shù))這種條件依舊不成立,所以查不到記錄
          SQL> select rownum,id,name from student where rownum >2;
          ROWNUM ID     NAME
          ---------- ------ ---------------------------------------------------
          那如何才能找到第二行以后的記錄呀。可以使用以下的子查詢方法來解決。注意子查詢中的rownum必須要有別名,否則還是不會查出記錄來,這是因為rownum不是某個表的列,如果不起別名的話,無法知道rownum是子查詢的列還是主查詢的列。
          SQL>select * from(select rownum no ,id,name from student) where no>2;
                  NO ID     NAME
          ---------- ------ ---------------------------------------------------
                   3 200003 李三
                   4 200004 趙四
          SQL> select * from(select rownum,id,name from student)where rownum>2;
              ROWNUM ID     NAME
          ---------- ------ ---------------------------------------------------
          (3)rownum對于小于某值的查詢條件
          如果想找到第三條記錄以前的記錄,當(dāng)使用rownum<3是能得到兩條記錄的。顯然rownum對于rownum<n((n>1的自然數(shù))的條件認(rèn)為是成立的,所以可以找到記錄。
          SQL> select rownum,id,name from student where rownum <3;
              ROWNUM ID     NAME
          ---------- ------ ---------------------------------------------------
          1 200001 張一
                  2 200002 王二
          綜上幾種情況,可能有時候需要查詢rownum在某區(qū)間的數(shù)據(jù),那怎么辦呀從上可以看出rownum對小于某值的查詢條件是人為true的,rownum對于大于某值的查詢條件直接認(rèn)為是false的,但是可以間接的讓它轉(zhuǎn)為認(rèn)為是true的。那就必須使用子查詢。例如要查詢rownum在第二行到第三行之間的數(shù)據(jù),包括第二行和第三行數(shù)據(jù),那么我們只能寫以下語句,先讓它返回小于等于三的記錄行,然后在主查詢中判斷新的rownum的別名列大于等于二的記錄行。但是這樣的操作會在大數(shù)據(jù)集中影響速度。
          SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2;
                  NO ID     NAME
          ---------- ------ ---------------------------------------------------
                   2 200002 王二
                   3 200003 李三
          (4)rownum和排序
          Oracle中的rownum的是在取數(shù)據(jù)的時候產(chǎn)生的序號,所以想對指定排序的數(shù)據(jù)去指定的rowmun行數(shù)據(jù)就必須注意了。
          SQL> select rownum ,id,name from student order by name;
              ROWNUM ID     NAME
          ---------- ------ ---------------------------------------------------
                   3 200003 李三
                   2 200002 王二
                   1 200001 張一
                   4 200004 趙四
          可以看出,rownum并不是按照name列來生成的序號。系統(tǒng)是按照記錄插入時的順序給記錄排的號,rowid也是順序分配的。為了解決這個問題,必須使用子查詢
          SQL> select rownum ,id,name from (select * from student order by name);
              ROWNUM ID     NAME
          ---------- ------ ---------------------------------------------------
                   1 200003 李三
                   2 200002 王二
                   3 200001 張一
                   4 200004 趙四
          這樣就成了按name排序,并且用rownum標(biāo)出正確序號(有小到大)

          posted @ 2011-11-17 16:46 redcoatjk 閱讀(328) | 評論 (0)編輯 收藏
           
          僅為個人理解.請指正
          Hibernate Session, 其作用無需多言.
          運用中為避免資源消耗,一般都會手動封裝一個HibernateUtil類(未使用Spring管理的前提下).
          該類的作用使Hibernate加載配置文件config, 創(chuàng)建sessionFactory等只運行一次.
          際運用中,經(jīng)常需要將當(dāng)前線程和session綁定.一般的用法為使用ThreadLocal: 在HibernateUtil類中封裝hibernate的管理.通過openSession取得
          session,并將其放入ThreadLocal變量中. 這樣業(yè)務(wù)邏輯中僅需通過工具類取得當(dāng)前線程對應(yīng)的session.使用完畢后,調(diào)用工具類closeSession方法將
          session關(guān)閉,當(dāng)前線程的ThreadLocal變量置為NULL. 保證線程歸還線程池復(fù)用后,ThreadLocal為空,以免出現(xiàn)導(dǎo)致其他線程訪問到本線程變量.
          后,Hibernate的SessionFactory提供獲取session的新方法getCurrentSession (獲得與當(dāng)前線程綁定的session). 內(nèi)部通過代理封裝,此方式得到的session
          不僅和當(dāng)前線程綁定,也無需手動開關(guān). 默認(rèn)在事務(wù)提交之后,session自動關(guān)閉. 需注意的是,必須在事務(wù)開啟的前提之下才可使用此種方式獲得的session.
          此外hibernate.cfg.xml配置文件中也許配置
          <property name="current_session_context_class">thread</property> 基于線程
          了,引入Spring之后.sessionfactory的創(chuàng)建等都交給spring管理.Spring也提供了HibernateTemplate,HibernateDaoSupport這樣的封裝方法.
          用戶可以不再考慮session的管理,事務(wù)的開啟關(guān)閉.只需配置事務(wù)即可.
          而所謂session關(guān)閉后,因延遲加載導(dǎo)致前臺無法顯示的問題以往解決方式為強制全部加載,現(xiàn)在也可通過在web.xml中配置
          org.springframework.orm.hibernate3.support.OpenSessionInViewFilter來解決.



          ------------------------------以下內(nèi)容為工地資料-------------------------------------------------------------------------------
          OpenSession : 手動打開,需手動關(guān)閉.[所以代碼中充斥著try catch --sf.openSession --打開事務(wù),提交-回滾 finall關(guān)閉session的代碼]
          threadlocal : hibernate給出的提示. 在HibernateUtil工具類中,new出threadlocal ,放入opensession.這樣可以使當(dāng)前線程綁定session.
          使用后需關(guān)閉session,將threadlocal中session變量置為null .
          3  getCurrentSession: hibernate3的新特性. 無需手動關(guān)閉session,自動獲取當(dāng)前線程的session,若無則新建之. 需在配置文件中配置thread屬性.表明和當(dāng)前線程綁定.
              參考網(wǎng)友資料,getCurrentSession模式,內(nèi)部開啟了session自動提交的功能且使用getCurrentSession的session,及時做load操作,也需要打開事務(wù).
          Title

          1 getCurrentSession創(chuàng)建的session會和綁定到當(dāng)前線程,而openSession不會。

          2 getCurrentSession創(chuàng)建的線程會在事務(wù)回滾或事物提交后自動關(guān)閉,而openSession必須手動關(guān)閉

          這里getCurrentSession本地事務(wù)(本地事務(wù):jdbc)時 要在配置文件里進(jìn)行如下設(shè)置

           * 如果使用的是本地事務(wù)(jdbc事務(wù))
           <property name="hibernate.current_session_context_class">thread</property>
           * 如果使用的是全局事務(wù)(jta事務(wù))
           <property name="hibernate.current_session_context_class">jta</property>

          getCurrentSession () 使用當(dāng)前的session
          openSession()         重新建立一個新的session

          在一個應(yīng)用程序中,如果DAO 層使用Spring 的hibernate 模板,通過Spring 來控制session 的生命周期,則首選getCurrentSession ()。

          使用Hibernate的大多數(shù)應(yīng)用程序需要某種形式的“上下文相關(guān)的” session,特定的session在整個特定的上下文范圍內(nèi)始終有效。然而,對不同類型的應(yīng)用程序而言,要為什么是組成這種“上下文”下一個定義通常 是困難的;不同的上下文對“當(dāng)前”這個概念定義了不同的范圍。在3.0版本 之前,使用Hibernate的程序要么采用自行編寫的基于 ThreadLocal的上下文session,要么采用HibernateUtil這樣的輔助類,要么采用第三方框架(比如Spring或Pico), 它們提供了基于代理(proxy)或者基于攔截器(interception)的上下文相關(guān)session。從3.0.1版本開始,Hibernate增加了SessionFactory.getCurrentSession()方法。一 開始,它假定了采用JTA事務(wù),JTA事務(wù)定義了當(dāng)前session的范圍和上下文(scope and context)。Hibernate開發(fā)團(tuán)隊堅信,因為有好幾個獨立的JTA TransactionManager實現(xiàn)穩(wěn)定可用,不論是否被部署到一個J2EE容器中,大多數(shù)(假若不是所有的)應(yīng)用程序都應(yīng)該采用JTA事務(wù)管理。 基于這一點,采用JTA的上下文相關(guān)session可以滿足你一切需要。

          更好的是,從3.1開始,SessionFactory.getCurrentSession()的后臺實現(xiàn)是可拔插的。因此,我們引入了新的擴展 接口 (org.hibernate.context.CurrentSessionContext)和新的配置參數(shù) (hibernate.current_session_context_class),以便對什么是“當(dāng)前session”的范圍和上下文(scope and context)的定義進(jìn)行拔插。

          請參閱 org.hibernate.context.CurrentSessionContext接口的Javadoc,那里有關(guān)于它的契約的詳細(xì)討論。它定義 了單一的方法,currentSession(),特定的實現(xiàn)用它來負(fù)責(zé)跟蹤當(dāng)前的上下文session。Hibernate內(nèi)置了此接口的兩種實現(xiàn)。

          org.hibernate.context.JTASessionContext - 當(dāng)前session根據(jù)JTA來跟蹤和界定。這和以前的僅支持JTA的方法是完全一樣的。詳情請參閱Javadoc。

          org.hibernate.context.ThreadLocalSessionContext - 當(dāng)前session通過當(dāng)前執(zhí)行的線程來跟蹤和界定。詳情也請參閱Javadoc。

          這兩種實現(xiàn)都提供了“每數(shù)據(jù)庫事務(wù)對應(yīng)一個session”的編程模型,也稱作每次請求一個session。Hibernate session的起始和終結(jié)由數(shù)據(jù)庫事務(wù)的生存來控制。假若你采用自行編寫代碼來管理事務(wù)(比如,在純粹的J2SE,或者 JTA/UserTransaction/BMT),建議你使用Hibernate Transaction API來把底層事務(wù)實現(xiàn)從你的代碼中隱藏掉。如果你在支持CMT的EJB容器中執(zhí)行,事務(wù)邊界是聲明式定義的,你不需要在代碼中進(jìn)行任何事務(wù)或 session管理操作。請參閱第 11 章 事務(wù)和并發(fā)一節(jié)來閱讀更多的內(nèi)容和示例代碼。

          hibernate.current_session_context_class 配置參數(shù)定義了應(yīng)該采用哪個org.hibernate.context.CurrentSessionContext實現(xiàn)。注意,為了向下兼容,如果未 配置此參數(shù),但是存在org.hibernate.transaction.TransactionManagerLookup的配 置,Hibernate會采用org.hibernate.context.JTASessionContext。一般而言,此參數(shù)的值指明了要使用的實 現(xiàn)類的全名,但那兩個內(nèi)置的實現(xiàn)可以使用簡寫,即"jta"和"thread"。

          1、getCurrentSession()與openSession()的區(qū)別?

          * 采用getCurrentSession()創(chuàng)建的session會綁定到當(dāng)前線程中,而采用openSession()
          創(chuàng)建的session則不會
          * 采用getCurrentSession()創(chuàng)建的session在commit或rollback時會自動關(guān)閉,而采用openSession()
          創(chuàng)建的session必須手動關(guān)閉
          2、使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置:
          * 如果使用的是本地事務(wù)(jdbc事務(wù))
          <property name="hibernate.current_session_context_class">thread</property>
          * 如果使用的是全局事務(wù)(jta事務(wù))
          <property name="hibernate.current_session_context_class">jta</property>

          利于ThreadLocal模式管理Session
             早在Java1.2推出之時,Java平臺中就引入了一個新的支持:java.lang.ThreadLocal,給我們在編寫多線程程序
             時提供了一種新的選擇。ThreadLocal是什么呢?其實ThreadLocal并非是一個線程的本地實現(xiàn)版本,它并不是一個Thread,
             而是thread local variable(線程局部變量)。也許把它命名為ThreadLocalVar更加合適。線程局部變量(ThreadLocal)
             其實的功用非常簡單,就是為每一個使用某變量的線程都提供一個該變量值的副本,是每一個線程都可以獨立地改變自己的副本,
             而不會和其它線程的副本沖突。從線程的角度看,就好像每一個線程都完全擁有一個該變量。
             ThreadLocal是如何做到為每一個線程維護(hù)變量的副本的呢?其實實現(xiàn)的思路很簡單,在ThreadLocal類中有一個Map,
             用于存儲每一個線程的變量的副本。比如下面的示例實現(xiàn)(為了簡單,沒有考慮集合的泛型):
          public class HibernateUtil {

          public static final ThreadLocal session =new ThreadLocal();

          public static final SessionFactory sessionFactory;
             static {
                try {
                  sessionFactory = new Configuration().configure().buildSessionFactory();
                } catch (Throwable ex) {
                     throw new ExceptionInInitializerError(ex);
                }   
          }

               public static Session currentSession() throws HibernateException {
                  Session s = session.get();
                  if(s == null) {
                    s = sessionFactory.openSession();
                    session.set(s);
                     }
                   return s;
                 }

              public static void closeSession() throws HibernateException {
                     Session s = session.get();
                  if(s != null) {
                      s.close();
                  }
                  session.set(null);
              }
          }

          以下為ThreadLocal的參考資料
          Title

           最近由于需要用到ThreadLocal,在網(wǎng)上搜索了一些相關(guān)資料,發(fā)現(xiàn)對ThreadLocal經(jīng)常會有下面幾種誤解

           一、ThreadLocal是java線程的一個實現(xiàn)
                ThreadLocal的確是和java線程有關(guān),不過它并不是java線程的一個實現(xiàn),它只是用來維護(hù)本地變量。針對每個線程,提供自己的變量版本,主要是為了避免線程沖突,每個線程維護(hù)自己的版本。彼此獨立,修改不會影響到對方。

           二、ThreadLocal是相對于每個session的

                  ThreadLocal顧名思義,是針對線程。在java web編程上,每個用戶從開始到會話結(jié)束,都有自己的一個session標(biāo)識。但是ThreadLocal并不是在會話層上。其 實,Threadlocal是獨立于用戶session的。它是一種服務(wù)器端行為,當(dāng)服務(wù)器每生成一個新的線程時,就會維護(hù)自己的 ThreadLocal。對于這個誤解,個人認(rèn)為應(yīng)該是開發(fā)人員在本地基于一些應(yīng)用服務(wù)器測試的結(jié)果。眾所周知,一般的應(yīng)用服務(wù)器都會維護(hù)一套線程池,也 就是說,對于每次訪問,并不一定就新生成一個線程。而是自己有一個線程緩存池。對于訪問,先從緩存池里面找到已有的線程,如果已經(jīng)用光,才去新生成新的線 程。所以,由于開發(fā)人員自己在測試時,一般只有他自己在測,這樣服務(wù)器的負(fù)擔(dān)很小,這樣導(dǎo)致每次訪問可能是共用同樣一個線程,導(dǎo)致會有這樣的誤解:每個 session有一個ThreadLocal

           三、ThreadLocal是相對于每個線程的,用戶每次訪問會有新的ThreadLocal

            理論上來說,ThreadLocal是的確是相對于每個線程,每個線程會有自己的ThreadLocal。但是上面已經(jīng)講到,一般的應(yīng)用服 務(wù)器都會維護(hù)一套線程池。因此,不同用戶訪問,可能會接受到同樣的線程。因此,在做基于TheadLocal時,需要謹(jǐn)慎,避免出現(xiàn) ThreadLocal變量的緩存,導(dǎo)致其他線程訪問到本線程變量 .[senngr:HibernateUtil工具類中,一般都是通過closesession的方法,里面將opensession對應(yīng)的session關(guān)閉.并將ThreadLocal變量置為NULL.這樣線程池中如果再將這個線程分配給別人,對應(yīng)的ThreadLocal是干凈的.]

           四、對每個用戶訪問,ThreadLocal可以多用
                  可以說,ThreadLocal是一把雙刃劍,用得來的話可以起到非常好的效果。但是,ThreadLocal如果用得不好,就會跟全局變量一樣。代碼不 能重用,不能獨立測試。因為,一些本來可以重用的類,現(xiàn)在依賴于ThreadLocal變量。如果在其他沒有ThreadLocal場合,這些類就變得不 可用了。個人覺得ThreadLocal用得很好的幾個應(yīng)用場合,值得參考

            1、存放當(dāng)前session用戶:quake want的jert

            2、存放一些context變量,比如webwork的ActionContext

            3、存放session,比如Spring hibernate orm的session

          posted @ 2011-11-02 01:37 redcoatjk 閱讀(17706) | 評論 (3)編輯 收藏
           
          http://space.itpub.net/9252210/viewspace-594453
          今天在做數(shù)據(jù)導(dǎo)出的時候,由于用戶名的密碼使用的是特殊字符,所以遇到了錯誤代碼:“EXP-00056: 遇到 ORACLE 錯誤 12154”,網(wǎng)上查找原因,需要用引號擴起來,但是os不同,方式也不同:

              windows os: exp username/"""password"""@devdb --3個雙引號擴密碼

              linux/unix os: exp 'username/"password"@devdb' --1個雙引號擴密碼,1個單引號擴全部

              實驗結(jié)果如下:
          1.創(chuàng)建帶有特殊字符密碼的用戶
          C:\Documents and Settings\Home>sqlplus /nolog
          SQL*Plus: Release 10.2.0.1.0 - Production on 星期四 5月 7 17:37:36 2009
          Copyright (c) 1982, 2005, Oracle.  All rights reserved.
          SQL> connsys/oracle@devdbas sysdba
          已連接。
          SQL> create user exp identified by "12345!@#$%";
          用戶已創(chuàng)建。
          SQL> grant connect, resource to exp;
          授權(quán)成功。
          SQL> conn exp/"12345!@#$%"@devdb2
          已連接。
          SQL> create table table1 as select * from dual;
          表已創(chuàng)建。
          SQL> exit
          2.windows os導(dǎo)出測試
          C:\Documents and Settings\Home>expexp/12345!@#$%@devdbfile=c:\exp.dmp wner=exp
          Export: Release 9.2.0.1.0 - Production on 星期四 5月 7 17:39:42 2009
          Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
          EXP-00056: 遇到 ORACLE 錯誤 12154
          ORA-12154: TNS: 無法處理服務(wù)名
          EXP-00000: 導(dǎo)出終止失敗
          C:\Documents and Settings\Home>exp exp/"12345!@#$%"@devdb2file=c:\exp.dmp wner=exp
          Export: Release 9.2.0.1.0 - Production on 星期四 5月 7 17:39:57 2009
          Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
          EXP-00056: 遇到 ORACLE 錯誤 12154
          ORA-12154: TNS: 無法處理服務(wù)名
          EXP-00000: 導(dǎo)出終止失敗
          C:\Documents and Settings\Home>exp exp/"""12345!@#$%"""@devdb2file=c:\exp.dmp wner=exp
          Export: Release 9.2.0.1.0 - Production on 星期四 5月 7 17:41:54 2009
          Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
          連接到: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
          With the Partitioning, Real Application Clusters, OLAP, Data Mining
          and Real Application Testing options
          已導(dǎo)出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集
          . 正在導(dǎo)出 pre-schema 過程對象和操作
          . 正在導(dǎo)出用戶 EXP 的外部函數(shù)庫名稱
          . 導(dǎo)出 PUBLIC 類型同義詞
          . 導(dǎo)出私有類型同義詞
          . 正在導(dǎo)出用戶 EXP 的對象類型定義
          即將導(dǎo)出 EXP 的對象 ...
          . 正在導(dǎo)出數(shù)據(jù)庫鏈接
          . 正在導(dǎo)出序號
          . 正在導(dǎo)出群集定義
          . 即將導(dǎo)出 EXP 的表通過常規(guī)路徑 ...
          . . 正在導(dǎo)出表                          TABLE1          1 行被導(dǎo)出
          . 正在導(dǎo)出同義詞
          . 正在導(dǎo)出視圖
          . 正在導(dǎo)出存儲的過程
          . 正在導(dǎo)出運算符
          . 正在導(dǎo)出引用完整性約束條件
          . 正在導(dǎo)出觸發(fā)器
          . 正在導(dǎo)出索引類型
          . 正在導(dǎo)出位圖, 功能性索引和可擴展索引
          . 正在導(dǎo)出后期表活動
          . 正在導(dǎo)出實體化視圖
          . 正在導(dǎo)出快照日志
          . 正在導(dǎo)出作業(yè)隊列
          . 正在導(dǎo)出刷新組和子組
          . 正在導(dǎo)出維
          . 正在導(dǎo)出 post-schema 過程對象和操作
          . 正在導(dǎo)出統(tǒng)計
          在沒有警告的情況下成功終止導(dǎo)出。

          3.linux/unix os導(dǎo)出測試
          [oracle@rac2 ~]$ expexp/12345!@#$%@devdbfile=./exp.dmp wner=exp
          -bash:!@#$%@devdb: event not found
          [oracle@rac2 ~]$ exp exp/"""12345!@#$%"""@devdbfile=./exp.dmp wner=exp
          -bash:!@#$%"""@devdb: event not found
          [oracle@rac2 ~]$exp 'exp/"12345!@#$%"@devdb'file=./exp.dmp wner=exp 
          Export: Release 10.2.0.4.0 - Production on Thu May 7 19:21:32 2009 
          Copyright (c) 1982, 2007, Oracle.  All rights reserved. 
          Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
          With the Partitioning, Real Application Clusters, OLAP, Data Mining
          and Real Application Testing options
          Export done in US7ASCII character set and AL16UTF16 NCHAR character set
          server uses ZHS16GBK character set (possible charset conversion)
          . exporting pre-schema procedural objects and actions
          . exporting foreign function library names for user EXP
          . exporting PUBLIC type synonyms
          . exporting private type synonyms
          . exporting object type definitions for user EXP
          About to export EXP's objects ...
          . exporting database links
          . exporting sequence numbers
          . exporting cluster definitions
          . about to export EXP's tables via Conventional Path ...
          . . exporting table                         TABLE1          1 rows exported
          . exporting synonyms
          . exporting views
          . exporting stored procedures
          . exporting operators
          . exporting referential integrity constraints
          . exporting triggers
          . exporting indextypes
          . exporting bitmap, functional and extensible indexes
          . exporting posttables actions
          . exporting materialized views
          . exporting snapshot logs
          . exporting job queues
          . exporting refresh groups and children
          . exporting dimensions
          . exporting post-schema procedural objects and actions
          . exporting statistics
          Export terminated successfully without warnings.

          posted @ 2011-10-19 17:03 redcoatjk 閱讀(697) | 評論 (0)編輯 收藏
           

          關(guān)于group by 的應(yīng)用問題  

          數(shù)據(jù)庫內(nèi)容為下面


           

          寫一SQL得出下面內(nèi)容:


           

          貼出SQL結(jié)果如下:(MySQL版本)

          create table gosin_temp(rq varchar(10),shengfu nchar(1));

          insert into gosin_temp values('2009-05-09','勝');
          insert into gosin_temp values('2009-05-09','勝');
          insert into gosin_temp values('2009-05-09','負(fù)');
          insert into gosin_temp values('2009-05-09','負(fù)');
          insert into gosin_temp values('2009-05-10','勝');
          insert into gosin_temp values('2009-05-10','負(fù)');
          insert into gosin_temp values('2009-05-10','負(fù)');

          select * from gosin_temp;

          得到結(jié)果的SQL:
          select a1.rq,a1.勝,b1.負(fù) from
          (select a.rq, count(a.shengfu) 勝 from gosin_temp a where a.shengfu='勝' group by a.rq) a1,
          (select b.rq, count(b.shengfu) 負(fù) from gosin_temp b where b.shengfu='負(fù)' group by b.rq) b1
          where a1.rq = b1.rq

          類似的題目還有很多,如:

             勝 負(fù)
          1 a b
          2 b a
          3 b a

          要求寫一SQL語句,輸出如下結(jié)果:
             勝 負(fù)
          a 1 2
          b 2 1

          其實都一樣 只要熟悉使用group by 就不覺得難了。

          posted @ 2011-08-25 17:12 redcoatjk 閱讀(230) | 評論 (0)編輯 收藏
           
          摘自:   http://www.iteye.com/topic/766418

          -----------------------------------------
          1,什么是Servlet
          2,Servlet有什么作用
          3,Servlet的生命周期
          4,Servlet怎么處理一個請求
          5,Servlet與JSP有什么區(qū)別
          6,Servlet里的cookie技術(shù)
          7,Servlet里的過濾器
          8,Servlet里的監(jiān)聽器

           


          一,什么是Servlet?


          Servlet是一個Java編寫的程序,此程序是基于Http協(xié)議的,在服務(wù)器端運行的(如tomcat),

           

          是按照Servlet規(guī)范編寫的一個Java類。



          二,Servlet有什么作用?


          主要是處理客戶端的請求并將其結(jié)果發(fā)送到客戶端。



          三,Servlet的生命周期?


          Servlet的生命周期是由Servlet的容器來控制的,它可以分為3個階段;初始化,運行,銷毀。

          初始化階段:


          1,Servlet容器加載servlet類,把servlet類的.class文件中的數(shù)據(jù)讀到內(nèi)存中。


          2,然后Servlet容器創(chuàng)建一個ServletConfig對象。ServletConfig對象包含了Servlet的初始化配置信息。


          3,Servlet容器創(chuàng)建一個servlet對象。


          4,Servlet容器調(diào)用servlet對象的init方法進(jìn)行初始化。



          運行階段:


          當(dāng)servlet容器接收到一個請求時,servlet容器會針對這個請求創(chuàng)建servletRequest和servletResponse對象。

           

          然后調(diào)用service方法。并把這兩個參數(shù)傳遞給service方法。Service方法通過servletRequest對象獲得請求的

           

          信息。并處理該請求。再通過servletResponse對象生成這個請求的響應(yīng)結(jié)果。然后銷毀servletRequest和

           

          servletResponse對象。我們不管這個請求是post提交的還是get提交的,最終這個請求都會由service方法來處理。


          web服務(wù)器接受到一個http請求后,web服務(wù)器會將請求移交給 servlet容器,servlet容器首先對所請求的URL進(jìn)行解析并根據(jù)
          web.xml 配置文件找到相應(yīng)的處理servlet,同時將request、response對象傳遞給它,servlet通過request對象可知道客戶端
          的請求 者、請求信息以及其他的信息等,servlet在處理完請求后會把所有需要返回的信息放入response對象中并返回到客戶端,
          servlet一旦處理 完請求,servlet容器就會刷新response對象,并把控制權(quán)重新返回給web服務(wù)器。

           


          銷毀階段:


          當(dāng)Web應(yīng)用被終止時,servlet容器會先調(diào)用servlet對象的destrory方法,然后再銷毀servlet對象,

           

          同時也會銷毀與servlet對象相關(guān)聯(lián)的servletConfig對象。我們可以在destroy方法的實現(xiàn)中,釋放

           

          servlet所占用的資源,如關(guān)閉數(shù)據(jù)庫連接,關(guān)閉文件輸入輸出流等。



          在這里該注意的地方:


          在servlet生命周期中,servlet的初始化和和銷毀階段只會發(fā)生一次,而service方法執(zhí)行的次數(shù)則取決于servlet被客戶

           

          端訪問的次數(shù)

           

           


          四,Servlet怎么處理一個請求?


          當(dāng)用戶發(fā)送一個請求到某個Servlet的時候,Servlet容器會創(chuàng)建一個ServletRequst和ServletResponse對象。

           

          在ServletRequst對象中封裝了用戶的請求信息,然后Servlet容器把ServletRequst和ServletResponse對象

           

          傳給用戶所請求的Servlet,Servlet把處理好的結(jié)果寫在ServletResponse中,然后Servlet容器把響應(yīng)結(jié)果傳

           

          給用戶。

           


          五,Servlet與JSP有什么區(qū)別?


          1,jsp經(jīng)編譯后就是servlet,也可以說jsp等于servlet。


          2,jsp更擅長頁面(表現(xiàn))。servlet更擅長邏輯編輯。 (最核心的區(qū)別)。


          3,在實際應(yīng)用中采用Servlet來控制業(yè)務(wù)流程,而采用JSP來生成動態(tài)網(wǎng)頁.在struts框架中,

           

          JSP位于MVC設(shè)計模式的視圖層,而Servlet位于控制層。

           


          六,Servlet里的cookie技術(shù)?


          cookies是一種WEB服務(wù)器通過瀏覽器在訪問者的硬盤上存儲信息的手段,是由Netscape公司開發(fā)出來的。


          cookie技術(shù)的好處:


              1,Cookie有效期限未到時,Cookie能使用戶在不鍵入密碼和用戶名的情況下進(jìn)入曾經(jīng)瀏覽過的一些站點。


              2,Cookie能使站點跟蹤特定訪問者的訪問次數(shù)、最后訪問時間和訪問者進(jìn)入站點的路徑。
             
          創(chuàng)建一個cookie

          Java代碼  收藏代碼
          1. //里面的兩個參數(shù)分別是cookie的名和cookie的值  
          2.   
          3. response.addCookie(new Cookie("abc","10000000"));  

           

          使用cookie

          Java代碼  收藏代碼
          1. Cookie[] cook =request.getCookies();//用一個Cookie數(shù)組來接收  
          2.   
          3. for(int j=0;j<cook.length;j++){//通過循環(huán)來打印Cookie  
          4.   
          5.         cook[j].getName()://取cookie的名    
          6.         cook[j].getValue()://去cookie的值  
          7.   
          8. }  
           


          七,Servlet里的過濾器?


          過濾器的主要作用


          1,任何系統(tǒng)或網(wǎng)站都要判斷用戶是否登錄。


          2,網(wǎng)絡(luò)聊天系統(tǒng)或論壇,功能是過濾非法文字


          3,統(tǒng)一解決編碼


          (2)怎么創(chuàng)建一個過濾器:

           

          1,生成一個普通的class類,實現(xiàn)Filter接口(javax.servlet.Filter;)。


          2,重寫接口里面的三個方法:init,doFilter,destroy。


          3,然后在web.xml配置過濾器。



          八,Servlet里的監(jiān)聽器?


          監(jiān)聽器的作用:自動執(zhí)行一些操作。

          三種servlet監(jiān)聽器:

           

          對request的監(jiān)聽。對session的監(jiān)聽。對application的監(jiān)聽。

          怎么創(chuàng)建一個session監(jiān)聽器:


          1,生成一個普通的class類,如果是對session的監(jiān)聽,則實現(xiàn)HttpSessionListener。


          2,然后重寫里面的五個方法:

           

          Java代碼  收藏代碼
          1. public void sessionCreated(HttpSessionEvent arg0) {} // 創(chuàng)建  
          2.   
          3. public void sessionDestroyed(HttpSessionEvent arg0) {} // 銷毀  
          4.   
          5. public void attributeAdded(HttpSessionEvent arg0) {} // 增加  
          6.   
          7. public void attributeRemoved(HttpSessionEvent arg0) {} // 刪除  
          8.   
          9. public void attributeReplaced(HttpSessionEvent arg0) {} // 替換 
          posted @ 2011-08-25 15:41 redcoatjk 閱讀(230) | 評論 (0)編輯 收藏
           
          這個寫的不錯.有的沒看懂.
          目前沒時間細(xì)看,暫時先轉(zhuǎn)載.
          摘自:
          http://www.jdon.com/artichect/state.htm

          ---------------------------------------------------

          板橋里人 http://www.jdon.com 2006/1/2(轉(zhuǎn)載請保留)

            這是一個實戰(zhàn)中非常重要但是容易被忽視的概念,說它重要,是因為它比數(shù)據(jù)庫重要;說它容易被忽視也是同樣的原因,它經(jīng)常被數(shù)據(jù)庫概念替代。

            如果你經(jīng)驗和經(jīng)歷中沒有狀態(tài)這個概念,極端地說:可能你的Java系統(tǒng)經(jīng)驗還未積累到一定程度,狀態(tài)是每個Java程序員深入Java系統(tǒng)后必然碰到的問題。

            本文我想試圖表達(dá)的是:狀態(tài)分兩種:活動的狀態(tài)對象和持久化的狀態(tài)。而數(shù)據(jù)庫中的數(shù)據(jù)只是狀態(tài)的一種持久化結(jié)果,而Java系統(tǒng) 運行時,我們更多的可能是和一種活動的狀態(tài)打交道,這種活動的狀態(tài)存在內(nèi)存中,而不是持久化到硬盤上,當(dāng)然,需要時你可以通過數(shù)據(jù)庫/文件持久化到硬盤上。

            但是,如果你以數(shù)據(jù)庫數(shù)據(jù)替代狀態(tài),那么就可能導(dǎo)致數(shù)據(jù)庫的頻繁訪問,而且 你的系統(tǒng)會變成一個非對象化的、緊耦合、到處是分散數(shù)據(jù)塊的糟糕系統(tǒng)。這樣的系統(tǒng)并不比傳統(tǒng)的兩層結(jié)構(gòu)好到哪里!也不會比Jsp里嵌入Java代碼偽三層系統(tǒng)高明到什么地方。

          什么是狀態(tài)?

            只要有對象就可能有狀態(tài),任何一個對象活動時,都有自己的狀態(tài)屬性,類的 字段屬性極有可能成為狀態(tài),我們現(xiàn)在經(jīng)常使用的Domain model其實就是一種 包含狀態(tài)的對象,如果你對狀態(tài)沒有深入掌握,就不可能真正掌握對象系統(tǒng)特點,或者是Domain Model的執(zhí)行情況。

            對于初學(xué)者,經(jīng)常會疑問:我是將數(shù)據(jù)放在HttpSession中還是Request中,這里 其實已經(jīng)開始接觸狀態(tài),一旦你接觸狀態(tài),你就要開始小心,因為你可能會將內(nèi)存泄漏的惡魔導(dǎo)引進(jìn)來。

            內(nèi)存泄漏的惡魔爆發(fā)時刻取決于你狀態(tài)的生存周期和系統(tǒng)并發(fā)訪問量。

            狀態(tài)的生存周期也就是包含這個狀態(tài)的對象的生命周期,在簡單系統(tǒng)中,我們只 需要通過new創(chuàng)建對象,然后它的消亡就會依靠JVM垃圾回收機制回收,但是事情會這么簡單嗎?

            狀態(tài)的危險還會發(fā)生在多線程環(huán)境下,當(dāng)多個線程對同一個內(nèi)存中狀態(tài)寫操作時,這時怎么辦?如果這個狀 態(tài)持久化在數(shù)據(jù)庫中,我們會依賴數(shù)據(jù)庫提供的強大事務(wù)機制防止這種并發(fā)死鎖,但是如果是在內(nèi)存中,你就很難辦,因此,我們就盡量避免發(fā)生這種多線程同時訪 問一個狀態(tài)的現(xiàn)象,而Singleton單例模式極容易發(fā)生這種現(xiàn)象,因此實踐中,單例模式是J2EE開發(fā)中需要避免的,相關(guān)帖子討論見:
          http://www.jdon.com/jive/article.jsp?forum=91&thread=17578

            我們接觸的Web容器或Jsp/Servlet本質(zhì)就是一個多線程,這也是很多初學(xué)者不知道的, 因為多線程編程是復(fù)雜或困難的,因此才有jsp/Servlet這樣的上層封裝,但是我們使用他們
          時,實際在進(jìn)行多線程編程。

            生命周期和多線程并發(fā)使得我們簡單的面向?qū)ο笙到y(tǒng)變得異常復(fù)雜和難以掌握起來。下面我從這個兩個角度,給出兩種模式思維解決之道。

          生命周期(Scope)

            生命周期(Scope)就是指狀態(tài)的活動周期,狀態(tài)對象是什么時候被創(chuàng)建;然后什么時候被銷毀,很顯然,如果狀態(tài)對象還沒有被創(chuàng)建或已經(jīng)被銷毀,你再 訪問這個狀態(tài)對象可能失敗,而狀態(tài)的生命周期控制是可能散落在運行程序的各個地方,如果不象狀態(tài)模式那樣進(jìn)行統(tǒng)一控制,有可能整個系統(tǒng)是危機四伏的。

            狀態(tài)的生命周期其實就是對象生命周期,更加細(xì)化地說:是Domain Model這個對象的生命周期。這在一個以領(lǐng)域模型為驅(qū)動的設(shè)計概念中不可回避的課題,而領(lǐng)域模型實戰(zhàn)的復(fù)雜性就復(fù)雜在此。

            狀態(tài)的生命周期在J2EE中目前有三種:Request/Session和 Application,Request是每個客戶端發(fā)出的一次請求,這是J2EE系統(tǒng)中最基本的事件激活單元, 當(dāng)服務(wù)器端推出一個頁面到客戶端時,意味著這個Request的結(jié)束。那么如果我們的狀態(tài)保存在Request中,意味著在request結(jié)束之前,這個 請求經(jīng)歷的任何一個環(huán)節(jié)都可以對這個狀態(tài)(對象)進(jìn)行操作。(掌握這個原理,對于你學(xué)習(xí)Struts和JSF很有幫助)

            如果是Session,則一直和該客戶端有關(guān),只要是該客戶端發(fā)出的每次request的任何環(huán)節(jié)都可以對這個狀態(tài)(對象)進(jìn)行操作。

            如果是Application,則意味著這個狀態(tài)是當(dāng)前Web項目的全局狀態(tài)。

            這三種狀態(tài)形式都是以將狀態(tài)保存在內(nèi)存中形式存在的,是和持久化狀態(tài)相對的。是一種內(nèi)存活動狀態(tài)。

            生命周期的選取當(dāng)然是越短越好,這樣,這個狀態(tài)對象就可以被自動銷毀,從而避免了
          大訪問量下的內(nèi)存泄漏,但是在大訪問量下,對象頻繁創(chuàng)建和銷毀是耗費性能的。

            那么,我們可能經(jīng)常使用HttpSession來保存狀態(tài),這時你極有可能造成內(nèi)存泄漏,我經(jīng)常在 Jdon論壇上看到將很多數(shù)據(jù)庫數(shù)據(jù)暫時保存在HttpSession中想法,這是相當(dāng)危險的,因為一旦并發(fā)用戶很多,相當(dāng)多的HttpSession包 含了狀態(tài),而狀態(tài)中有可能有更多其他引用,因此內(nèi)存很快會爆滿,或者垃圾回收機制頻繁啟動,造成應(yīng)用系統(tǒng)運行暫停或緩慢。

            當(dāng)你將狀態(tài)放入HttpSession時,難道沒有考慮將其手工消除嗎?你要知道所有Web容器 (Tomcat/Weblogic等)都不會自動替你清除那些你可能不用的狀態(tài)對象啊。如果每個人只管新增元素,不管重整或管理,這個系統(tǒng)能不變得混亂 嗎?代碼上這種現(xiàn)象我們是通過Refactoring等結(jié)構(gòu)/行為模式來解決,那么在運行時的狀態(tài)管理呢?

            狀態(tài)管理模式或者說對象管理模式正是解決這種問題的。

             按照該模式,你必須手工自己管理放在HttpSession的狀態(tài),比如你為每個HttpSession
          設(shè)立一個狀態(tài)容器最大尺寸,當(dāng)超過這個尺寸時,你需要將不用的狀態(tài)從容器去除, 但是如果這個客戶端在Session失效期內(nèi)又來訪問這個狀態(tài)怎么辦?那么你可能需要先臨時將狀態(tài)序列化保存到硬盤上,等Session失效期到達(dá)后再真正刪除。

            是不是覺得很麻煩?
            捷徑是有:
            1. 盡量少使用HttpSession保存狀態(tài),這對集群環(huán)境也是有利的,見該貼討論:
          http://www.jdon.com/jive/article.jsp?forum=121&thread=22282
          那么這些狀態(tài)放在哪里?使用Application的緩存中,

            2. 使用狀態(tài)管理中間件,目前有幾個選擇:EJB的有態(tài)Bean;NanoContainer之類狀態(tài)相關(guān)的微容器。那么Spring可以嗎?目前沒有發(fā)現(xiàn)有 該功能,甚至在Spring容器內(nèi)無法直接使用Session性質(zhì)的狀態(tài),只能通過線程級別的ThreadLocal來實現(xiàn)(對不起,你又要開始回到遠(yuǎn)古 的匯編線程時代了);而Jdon框架則可以。

            下面我們談?wù)凙pplication的狀態(tài),在這個范圍內(nèi),一個對象狀態(tài)可以被多個用戶反復(fù)訪問,在這個級別,狀態(tài)類似數(shù)據(jù)庫中數(shù)據(jù),因為可以使用數(shù)據(jù)庫來替代這個級別的狀態(tài),所以將狀態(tài)放入緩存這個深層次技術(shù)被大多數(shù)初學(xué)者忽視了,甚至產(chǎn)生了對數(shù)據(jù)庫依賴心理。

          緩存中的狀態(tài)

            雖然我們將狀態(tài)保存在Application中,但是我們不可避免還是遇到Session同樣的狀態(tài)管理問題,這個問題所幸的是有專門緩存中間件解決 了,當(dāng)然,在一個多服務(wù)器集群系統(tǒng),如果一個客戶端在一個服務(wù)器中存放了狀態(tài),那么能否在另外一個服務(wù)器的內(nèi)存中訪問到呢?回答是肯定的,前提是你必須使 用分布式緩存系統(tǒng)。

            目前分布式緩存系統(tǒng)是靠EJB服務(wù)器完成,當(dāng)JBoss 5在2006變成完全解耦、可肢解時,
          我們就可以使用原本只支持EJB的JBoss分布式緩存系統(tǒng)來支持我們的普通JavaBeans了(POJO)。這其中目前可能會花費一些力氣,因為還沒有一個統(tǒng)一的POJO構(gòu)件接口標(biāo)準(zhǔn),我相信以后
          可能會有。

            如果你不想花費力氣,而且可能就只是一臺服務(wù)器,可以通過雙核芯片提升性能,那么單態(tài)緩存如果實現(xiàn)?很簡單,使用一個緩存產(chǎn)品如OsCache等,將其設(shè)定保存在 Application中,或者在web.xml中進(jìn)行一下簡單的配置即可。

            但是,這時你可能碰到另外一個問題:狀態(tài)的唯一標(biāo)識,如何通過唯一標(biāo)識從緩存中那么
          多對象狀態(tài)中取出你要的那一個呢?比較瑣碎。

            有沒有一個框架幫助你省卻這些麻煩,當(dāng)然推薦Jdon Framework,只要將包含狀態(tài)的類(主要是Domain Model)繼承特定的類或接口(接口在1.4版本實現(xiàn))即可,這個類的對象運行時就會被緩存或從緩存中讀取,再也無需你照料緩存了,就這么簡單。

            當(dāng)然,Jdon Framework的底層緩存器是可以被替代,使用你喜歡的緩存產(chǎn)品,因為jdon
          Framework是基于Ioc設(shè)計,構(gòu)件之間是完全解耦、可徹底肢解,能夠通過配置替代和更換的。
          如果你不明白這個道理,需要好好研究一下Ioc模式帶給我們革命性的新變化。

            從以上也可以看出:java復(fù)雜性還在于我們需要在編碼時,卻要想象其運行時的情形。而這種翻譯聯(lián)想沒有深厚的實踐功底,是很難順利完成的。

          狀態(tài)管理中間件

            自從J2EE開辟中間件時代以來,就有相當(dāng)多的高級中間件提供與具體應(yīng)用無關(guān)的通用功能,狀態(tài)管理中間件很早就有之,EJB的有態(tài)Session Bean是一個代表。

            一個中間件不但要有良好的松耦合設(shè)計,我們暫時稱為靜態(tài)設(shè)計;更要有優(yōu)秀的動態(tài)設(shè)計,例如狀態(tài)管理就屬于一種動態(tài)設(shè)計。

            當(dāng)然,如果你比較謙虛,不但要選擇一些靜態(tài)設(shè)計很好的框架或中間件;而且還要依賴一些擁有良好的動態(tài)運行管理的中間件。

            EJB無論是EJB1.X/EJB2.X/EJB3.X.在狀態(tài)管理上要更加優(yōu)秀,當(dāng)然EJB3.X又吸收了優(yōu)秀的靜態(tài)設(shè)計概念,但是因為需要有一個具體服務(wù)器實現(xiàn)過程,這個過程中存在一些陷阱,如In-Box問題等。

            Spring無疑是一個靜態(tài)設(shè)計非常優(yōu)秀框架,它一直在AOP上孜孜不倦,力圖探索一條從AOP角度進(jìn)行動態(tài)運行管理干預(yù)捷徑,相信會有驚人結(jié)果,當(dāng)然,這種細(xì)粒度的AOP需要實踐檢驗,當(dāng)然如果整入JDK 6.0就更好。

            而Jdon Framework則試圖在目前兩者之間尋求了一個平衡,既有Ioc/AOP優(yōu)秀的靜態(tài)設(shè)計,雖然在AOP上不及Spring前衛(wèi);但提供了切實Session和Cache狀態(tài)管理;

            如果你不需要EJB的分布式多服務(wù)器集群功能;又不是AOP的超級粉絲,無疑使用Jdon Framework之類的框架無疑是簡化方便的。

          狀態(tài)設(shè)計的難點

            最后,我不得不重申,并不是有了良好的狀態(tài)管理框架就可以高枕無憂了,狀態(tài)的設(shè)計其實是我們每個項目必須面臨的可變課題,如果狀態(tài)復(fù)雜了可以使用狀態(tài)模式對付,可惜往往狀態(tài)不夠復(fù)雜。

            一個對象本身屬性和狀態(tài)是應(yīng)該耦合在一起,還是進(jìn)行分離,屬性和狀態(tài)沒有明顯的涇渭分明的界限,我們舉一個例子:

            論壇Forum這個對象,它有一些字段屬性,如論壇名稱、論壇描述,還有其他一些相關(guān)屬性:如該論壇 的最新發(fā)帖;該論壇的發(fā)貼量,后兩者好像也是論壇字段,但是他們可能經(jīng)常變化的,應(yīng)該屬于狀態(tài),那么狀態(tài)和Forum這個主體對象是什么關(guān)系?是將該論壇 的最新發(fā)帖和該論壇的發(fā)貼量兩個字段并入Forum這個Domain Model中,還是應(yīng)該單獨建立一個狀態(tài)對象?如果進(jìn)行分離,分離的依據(jù)是什么?

            當(dāng)然,這里分離的依據(jù)是因為對象的生存周期不同。對于我們熟悉的課題,我們能夠馬上分辨出其中的生存周期,如果是不熟悉領(lǐng)域的建模呢?

            所以,大家已經(jīng)明白:狀態(tài)設(shè)計的難點是:如何粒度細(xì)化地創(chuàng)建模型對象;然后分辨出其中動態(tài)的狀態(tài)性質(zhì)。這是域建模實戰(zhàn)中一個難點。

            很多人問我:你提倡的域建模、設(shè)計模式和框架是什么意思?為什么說他們是Java開發(fā)設(shè)計的三件寶呢?或者說三個典型知識點呢?我想通過本篇我已經(jīng)通過狀態(tài)這個概念稍微解釋了域建模的一些特點。

            當(dāng)前,MDA中的四色原型模式Archetype將幫助我們更好地分辨出類的屬性、狀態(tài)和行為,這是一場帶來以后十年的軟件革命,
          posted @ 2011-08-25 15:38 redcoatjk 閱讀(182) | 評論 (0)編輯 收藏
           

          我對瀏覽器請求流程的理解:

          (1) 訪問流程:

          (1.1) 系統(tǒng)運行在某web容器,Tomcat(其運行和weblogic不同,Tomcat只有一個進(jìn)程).

                其預(yù)設(shè)有初始的線程數(shù).

          (1.2) 瀏覽器打開某網(wǎng)站,網(wǎng)站及給其分配一個sessionID(頁面隱式的發(fā)起request, Tomcat

                某個特定的監(jiān)聽線程給予response一個sessionid). sessionid用以識別本次訪問.

          (1.3) 用戶點擊登錄/注冊, 瀏覽器發(fā)起一個新的request, Tomcat線程池中空閑的線程進(jìn)行

                 處理. 反饋結(jié)果于前臺展現(xiàn).如線程池中線程不足,Tomcat每次按照一定規(guī)則創(chuàng)建出更多的空閑線程(其初始值,增加值,及最大值依據(jù)配置文件/JDK/硬件).

          posted @ 2011-08-25 11:37 redcoatjk 閱讀(225) | 評論 (0)編輯 收藏
           
          來源:
          http://www.iteye.com/topic/960652
          http://godsend-jin.iteye.com/blog/1004386
          --------------------------------------------------------------------

          最近在做登錄和權(quán)限控制模塊,用到了session,發(fā)現(xiàn)session的好多方法都不熟悉,而且以前也聽說過JsessionId 之類session竊取的事,

          對這些一直都是一知半解。今天索性google了很多資料,先上sun的官網(wǎng)去看session的文檔了解一些方法,又找了別人關(guān)于session的看法。

          總結(jié)如下:

                1,session是什么?  what

                    session經(jīng)常譯為會話,以打電話為例,從開始撥號到掛斷電話就是你會話的生存周期。

                2,session 做什么用的  why?

                    首先舉個例子:

                          咖啡店舉行 消費滿5杯咖啡贈送一杯的活動,可每個人一次消費5杯的時候非常少。這時候有3種辦法:

                          1,店員看到每個顧客時都能記住其消費了多少杯,從而給其優(yōu)惠,這是協(xié)議本身具有狀態(tài)

                          2,給每個顧客一個卡片,上面記錄顧客的每次消費,這是客戶端保存狀態(tài)

                          3,給每個顧客一個卡片,卡片上只有一個編號,顧客每次的消費記錄在店里,這就是 服務(wù)端有狀態(tài)

                    而http本身是無狀態(tài)的,所以我們只能使用2,3中方法,來保存一些信息。

                    實際采用的是第3種方法,服務(wù)器段保存一次會話所有的信息,并生成一個唯一的id,這個id沒有規(guī)律而且不會重復(fù),將這個id傳回到客戶段,

          保存到cookie中。每次訪問服務(wù)器時,客戶端都會偷偷將這個id傳到服務(wù)器,服務(wù)器根據(jù)id查到這次會話保存的內(nèi)容。就能實現(xiàn)會話中共享一些數(shù)據(jù)。

               3,session怎樣創(chuàng)建和銷毀 ? how

                   session是保存在內(nèi)存中的,所以會有一些性能上的影響。因此本著這個原則,session是只有在使用到的時候才會被創(chuàng)建,如果始終沒有用到

          session,這個session是永遠(yuǎn)不會被創(chuàng)建的。

                  比如: 訪問servlet ,只要你代碼中沒有 request.getSession()或request.getSession(true);這兩行是等價的,那session是不會創(chuàng)建。

          又 當(dāng)你訪問靜態(tài)頁面時,根本不會生成servlet,所以也不會創(chuàng)建session。

                 下面解釋一些疑惑: session是第一次請求時創(chuàng)建的?

            大家都知道 jsp是被編譯成servlet才執(zhí)行的,問題就在jsp編譯的過程。

           jsp中有個<%@ page session="true/false"%> 這個開關(guān)表示是否創(chuàng)建session,當(dāng)你不寫這行時,它會默認(rèn)給你加上這句。所以會造成上面的疑惑。

          當(dāng)然還有一些標(biāo)簽中可能有g(shù)etSession()操作,會產(chǎn)生一些不必要的session。

                 session只能在服務(wù)端銷毀,有三種途徑: 1,到達(dá)session的最大請求間隔時間時,2,session。invalidate()

           3,服務(wù)器進(jìn)程當(dāng)?shù)簟?/p>

                 這里也有一些疑惑: 瀏覽器關(guān)閉時,session就會注銷。

                 首先瀏覽器關(guān)閉時,瀏覽器并沒有給服務(wù)器發(fā)送任何消息,所以服務(wù)器不會知道瀏覽器何時關(guān)閉了。

           上面我們知道取得session 是因為瀏覽器cookie中有sessionid,而普通cookie通常會是會話cookie,也就是說瀏覽器關(guān)閉時,這個cookie會被注銷,

          所以當(dāng)你再訪問服務(wù)器時就沒有sessionid了,所以造成session關(guān)閉了的假象,如果昵稱通過特殊方法將sessionid傳遞給服務(wù)器,你會發(fā)現(xiàn)session還在。

          如果想讓cookie保存時間長一些,就需要手動指定cookie的過期時間

           

          4,實際項目中的難點:

               1,瀏覽器禁用cookie

                這就沒辦法保存sessionid了,可以采用url重寫,轉(zhuǎn)發(fā),加隱藏字段等方法來將sessionid傳給服務(wù)器。

               如:  baidu.com:jsessionid=adfasdfasdfasdfasdfafdadf?asdfasdf

                       baidu.com?jsessionid=asdfasdfasdfadsfad&&adfdf

           這根據(jù)服務(wù)器的不同實現(xiàn),第一種可以將普通參數(shù)區(qū)分開。

           

               2,多人共用session的問題

                  例: a 訪問 baidu.com ,但他沒有帳號,于是他將連接 baidu.com/login.jsp?jsessionid=adsfasdfad(這個a的sessionid) 發(fā)給B, B登錄

          后,a就相當(dāng)于用b的帳號登錄了。你們可以在在本地試試。

                  解決方法: 當(dāng)發(fā)現(xiàn)通過sessionid從url指定時, 創(chuàng)建一個新的session,將舊session的信息復(fù)制到 新sessoin中,然后將新session注銷。

          就能防止上面那種情況了。

              3,一個帳號多地方登錄

                 比如: 你用abc帳號登錄了baidu.com,有打開了一個瀏覽器,又用abc帳號登錄了一次。當(dāng)不設(shè)計敏感操作時,這無所謂,而當(dāng)你做一些敏感操

          作時就必須禁止這樣情況,防止同時操作,造成重復(fù)操作,或者數(shù)據(jù)損壞。

               解決方法: 監(jiān)聽session,將username和sessionid對應(yīng)起來,當(dāng)username再次登錄時,注銷掉以前的session,保存現(xiàn)在的session,這也是

          一種比較不錯的方案。

           

          這是 sghcel 畫的圖,挺不錯的:

           



          其他:
           1session在何時被創(chuàng)建 
              一個常見的誤解是以為session在有客戶端訪問時就被創(chuàng)建,然而事實是直到某server端程序調(diào)用 HttpServletRequest.getSession(true)這樣的語句時
          才被創(chuàng)建,注意如果
          JSP沒有顯示的使用 <%@page session="false"%> 關(guān)閉session,則JSP文件在編譯成Servlet時將會自動加上這樣一條語句
          HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的session對象的來歷。 

             
          由于session會消耗內(nèi)存資源,因此,如果不打算使用session,應(yīng)該在所有的JSP中關(guān)閉它。


              2
          session何時被刪除
            綜合前面的討論,session在下列情況下被刪除a.程序調(diào)用HttpSession.invalidate();b.距離上一次收到客戶端發(fā)送的session id時間間隔超過了session
          超時設(shè)置
          ;c.服務(wù)器進(jìn)程被停止(非持久session


              3
          、如何做到在瀏覽器關(guān)閉時刪除session
          Title
            嚴(yán)格的講,做不到這一點。可以做一點努力的辦法是在所有的客戶端頁面里使用javascript代碼window.oncolose來監(jiān)視瀏覽器的關(guān)閉動作,然后向服務(wù)器發(fā)送
          一個請求來刪除
          session。但是對于瀏覽器崩潰或者強行殺死進(jìn)程這些非常規(guī)手段仍然無能為力。


              4
          、有個HttpSessionListener是怎么回事 

             
          你可以創(chuàng)建這樣的listener去監(jiān)控session的創(chuàng)建和銷毀事件,使得在發(fā)生這樣的事件時你可以做一些相應(yīng)的工作。注意是session的創(chuàng)建和銷毀動作觸發(fā)listener
          而不是相反。類似的與
          HttpSession有關(guān)的listener還有 HttpSessionBindingListenerHttpSessionActivationListener HttpSessionAttributeListener 

              5
          、存放在session中的對象必須是可序列化的嗎 


           
          不是必需的。要求對象可序列化只是為了session能夠在集群中被復(fù)制或者能夠持久保存或者在必要時server能夠暫時把session交換出內(nèi)存。
          Weblogic Serversession中放置一個不可序列化的對象在控制臺上會收到一個警告。我所用過的某個iPlanet版本如果session中有不可序列化的對象,
          session銷毀時會有一個Exception,很奇怪。


              6
          、如何才能正確的應(yīng)付客戶端禁止cookie的可能性
           
              對所有的URL使用URL重寫,包括超鏈接,formaction,和重定向的URL,具體做法參見[6]
          http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770


              7
          、開兩個瀏覽器窗口訪問應(yīng)用程序會使用同一個session還是不同的session 

             
          參見第三小節(jié)對cookie的討論,對session來說是只認(rèn)id不認(rèn)人,因此不同的瀏覽器,不同的窗口打開方式以及不同的cookie存儲方式都會對這個問題
          的答案有影響。
           

              8
          、如何防止用戶打開兩個瀏覽器窗口操作導(dǎo)致的session混亂 
          這個問題與防止表單多次提交是類似的,可以通過設(shè)置客戶端的令牌來解決。就是在服務(wù)器每次生成一個不同的id返回給客戶端,同時保存在session里,
          客戶端提交表單時必須把這個
          id也返回服務(wù)器,程序首先比較返回的id與保存在session里的值是否一致,如果不一致則說明本次操作已經(jīng)被提交過了。
          可以參看《
          J2EE核心模式》關(guān)于表示層模式的部分。需要注意的是對于使用javascript window.open打開的窗口,一般不設(shè)置這個id,或者使用單獨的id
          以防主窗口無法操作,建議不要再
          window.open打開的窗口里做修改操作,這樣就可以不用設(shè)置。


              9
          、為什么在Weblogic Server中改變session的值后要重新調(diào)用一次session.setValue 


          做這個動作主要是為了在集群環(huán)境中提示Weblogic Server session中的值發(fā)生了改變,需要向其他服務(wù)器進(jìn)程復(fù)制新的session值。


             10HttpSession 和 hibernate session 有什么區(qū)別?
          httpSession :

          它的產(chǎn)生:J2EE的Web程序在運行的時候,會給每一個新的訪問者建立一個HttpSession,這個Session是用戶身份的唯一表示。注意,是容器

          (Tomcat,Resin)自動創(chuàng)建的。

          用途:存放這個用戶的一些經(jīng)常被用到的信息,例如:用戶名,權(quán)限。例如在購物車程序里,存放用戶買的商品。

          銷毀:一定時間(跟容器有關(guān))內(nèi),用戶無任何動作,session自動銷毀。

          得到的方法:
          HttpSession session = request.getSession();
          常用方法setAttribute
          session.setAttribute(key,value);
          這樣在另一個jsp或者Servlet里,可以用
          session.getAttribute(key);得到value
          類似一個Map


          hibernate session

          它是hibernate操作數(shù)據(jù)庫的一個句柄對象。它跟上面那個Session唯一的相似處就是名字有點像,其他沒任何一樣的地方。
          它是hibernate表示操作數(shù)據(jù)庫的一個會話

           

          posted @ 2011-08-25 11:22 redcoatjk 閱讀(1247) | 評論 (0)編輯 收藏
           

          AOP術(shù)語介紹

          1. 正常的編程為從上到下的調(diào)用,執(zhí)行



          2. 加入了安全性檢查,日志這樣的代碼. 這是一個橫切的問題,其于正常的業(yè)務(wù)毫無關(guān)系.

          橫切的問題會散布在代碼的各個角落
          .


          3.這個橫切就是橫切性的關(guān)注點: Cross cutting concern





          4.
          將橫切的關(guān)注點都放在一個類中(如動態(tài)代理項目中的SecurityHandler.java).這個類就叫做切面.

             對橫切關(guān)注點進(jìn)行模塊化,這個模塊化的類就叫做切面類(Aspect對應(yīng)的類) ,


           

           

          5. 在切面類中對某個問題如日志或安全性檢查的具體實現(xiàn)方法,叫做橫切關(guān)注點的具體實現(xiàn)(稱為Advice).






           

           

          6. 這個Advice可以進(jìn)行分類. :在業(yè)務(wù)方法執(zhí)行之前,之后.異常時候……


           

          7. Advice應(yīng)用的目標(biāo)方法范圍(那些方法之前,之后,異常….)這個過濾范圍叫做切入點Pointcut()


           

          8 .植入

          Advice應(yīng)用的目標(biāo)方法的過程叫做植入(Weave)

          Spring只支持針對業(yè)務(wù)方法執(zhí)行前,執(zhí)行后進(jìn)行植入. 即只支持方法級別的植入

          植入的地方就叫做連接點.

          SpringAop是使用代理模式.

           

          橫切問題的處理思路:

          發(fā)現(xiàn)橫切性的問題,將其模塊化(切片).然后形成切片類,在其中實現(xiàn)這些橫切性的功能.

          posted @ 2011-06-26 21:58 redcoatjk 閱讀(208) | 評論 (0)編輯 收藏
           
          摘自:
          http://www.iteye.com/topic/257191

          -----------------
          今天下午研究了半天hashcode()和equals()方法,終于有了一點點的明白,寫下來與大家分享(zhaoxudong 2008.10.23晚21.36)。
          1. 首先equals()和hashcode()這兩個方法都是從object類中繼承過來的。
          equals()方法在object類中定義如下:
            public boolean equals(Object obj) {
          return (this == obj);
          }
          很明顯是對兩個對象的地址值進(jìn)行的比較(即比較引用是否相同)。但是我們必需清楚,當(dāng)String 、Math、還有Integer、Double。。。。等這些封裝類在使用equals()方法時,已經(jīng)覆蓋了object類的equals()方法。比 如在String類中如下:
            public boolean equals(Object anObject) {
          if (this == anObject) {
              return true;
          }
          if (anObject instanceof String) {
              String anotherString = (String)anObject;
              int n = count;
              if (n == anotherString.count) {
          char v1[] = value;
          char v2[] = anotherString.value;
          int i = offset;
          int j = anotherString.offset;
          while (n-- != 0) {
              if (v1[i++] != v2[j++])
          return false;
          }
          return true;
              }
          }
          return false;
          }
          很明顯,這是進(jìn)行的內(nèi)容比較,而已經(jīng)不再是地址的比較。依次類推Double、Integer、Math。。。。等等這些類都是重寫了equals()方法的,從而進(jìn)行的是內(nèi)容的比較。當(dāng)然了基本類型是進(jìn)行值的比較,這個沒有什么好說的。
          我們還應(yīng)該注意,Java語言對equals()的要求如下,這些要求是必須遵循的:
          • 對稱性:如果x.equals(y)返回是“true”,那么y.equals(x)也應(yīng)該返回是“true”。
          • 反射性:x.equals(x)必須返回是“true”。
          • 類推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也應(yīng)該返回是“true”。
          • 還有一致性:如果x.equals(y)返回是“true”,只要x和y內(nèi)容一直不變,不管你重復(fù)x.equals(y)多少次,返回都是“true”。
          • 任何情況下,x.equals(null),永遠(yuǎn)返回是“false”;x.equals(和x不同類型的對象)永遠(yuǎn)返回是“false”。
          以上這五點是重寫equals()方法時,必須遵守的準(zhǔn)則,如果違反會出現(xiàn)意想不到的結(jié)果,請大家一定要遵守。
          2. 其次是hashcode() 方法,在object類中定義如下:
            public native int hashCode();
          說明是一個本地方法,它的實現(xiàn)是根據(jù)本地機器相關(guān)的。當(dāng)然我們可以在自己寫的類中覆蓋hashcode()方法,比如String、 Integer、Double。。。。等等這些類都是覆蓋了hashcode()方法的。例如在String類中定義的hashcode()方法如下:
              public int hashCode() {
          int h = hash;
          if (h == 0) {
              int off = offset;
              char val[] = value;
              int len = count;

                      for (int i = 0; i < len; i++) {
                          h = 31*h + val[off++];
                      }
                      hash = h;
                  }
                  return h;
          }
          解釋一下這個程序(String的API中寫到):
          s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
          使用 int 算法,這里 s[i] 是字符串的第 i 個字符,n 是字符串的長度,^ 表示求冪。(空字符串的哈希碼為 0。)

          3.這里我們首先要明白一個問題:
          equals()相等的兩個對象,hashcode()一定相等;
          equals()不相等的兩個對象,卻并不能證明他們的hashcode()不相等。換句話說,equals()方法不相等的兩個對象,hashcode()有可能相等。(我的理解是由于哈希碼在生成的時候產(chǎn)生沖突造成的)。
          反過來:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。解釋 下第3點的使用范圍,我的理解是在object、String等類中都能使用。在object類中,hashcode()方法是本地方法,返回的是對象的 地址值,而object類中的equals()方法比較的也是兩個對象的地址值,如果equals()相等,說明兩個對象地址值也相等,當(dāng)然 hashcode()也就相等了;在String類中,equals()返回的是兩個對象內(nèi)容的比較,當(dāng)兩個對象內(nèi)容相等時,
          Hashcode()方法根據(jù)String類的重寫(第2點里面已經(jīng)分析了)代碼的分析,也可知道hashcode()返回結(jié)果也會相等。以此類 推,可以知道Integer、Double等封裝類中經(jīng)過重寫的equals()和hashcode()方法也同樣適合于這個原則。當(dāng)然沒有經(jīng)過重寫的 類,在繼承了object類的equals()和hashcode()方法后,也會遵守這個原則。

          4.談到hashcode()和equals()就不能不說到hashset,hashmap,hashtable中的使用,具體是怎樣呢,請看如下分析:
          Hashset是繼承Set接口,Set接口又實現(xiàn)Collection接口,這是層次關(guān)系。那么hashset是根據(jù)什么原理來存取對象的呢?
          在hashset中不允許出現(xiàn)重復(fù)對象,元素的位置也是不確定的。在hashset中又是怎樣判定元素是否重復(fù)的呢?這就是問題的關(guān)鍵所在,經(jīng)過一下午的查詢求證終于獲得了一點啟示,和大家分享一下,在java的集合中,判斷兩個對象是否相等的規(guī)則是:
          1),判斷兩個對象的hashCode是否相等
                如果不相等,認(rèn)為兩個對象也不相等,完畢
                如果相等,轉(zhuǎn)入2)
          (這一點只是為了提高存儲效率而要求的,其實理論上沒有也可以,但如果沒有,實際使用時效率會大大降低,所以我們這里將其做為必需的。后面會重點講到這個問題。)
          2),判斷兩個對象用equals運算是否相等
                如果不相等,認(rèn)為兩個對象也不相等
                如果相等,認(rèn)為兩個對象相等(equals()是判斷兩個對象是否相等的關(guān)鍵)
          為什么是兩條準(zhǔn)則,難道用第一條不行嗎?不行,因為前面已經(jīng)說了,hashcode()相等時,equals()方法也可能不等,所以必須用第2條準(zhǔn)則進(jìn)行限制,才能保證加入的為非重復(fù)元素。
          比如下面的代碼:

          public static void main(String args[]){
          String s1=new String("zhaoxudong");
          String s2=new String("zhaoxudong");
          System.out.println(s1==s2);//false
          System.out.println(s1.equals(s2));//true
          System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode()
          System.out.println(s2.hashCode());
          Set hashset=new HashSet();
          hashset.add(s1);
          hashset.add(s2);
          /*實質(zhì)上在添加s1,s2時,運用上面說到的兩點準(zhǔn)則,可以知道hashset認(rèn)為s1和s2是相等的,是在添加重復(fù)元素,所以讓s2覆蓋了s1;*/
          Iterator it=hashset.iterator();
                      while(it.hasNext())
                      {
                       System.out.println(it.next());
                      }
          最后在while循環(huán)的時候只打印出了一個”zhaoxudong”。
          輸出結(jié)果為:false
                      true
                      -967303459
                      -967303459
          這是因為String類已經(jīng)重寫了equals()方法和hashcode()方法,所以在根據(jù)上面的第1.2條原則判定時,hashset認(rèn)為它們是相等的對象,進(jìn)行了重復(fù)添加。
          但是看下面的程序:
          import java.util.*;
          public class HashSetTest
          {
             public static void main(String[] args)
              {
                           HashSet hs=new HashSet();
                           hs.add(new Student(1,"zhangsan"));
                           hs.add(new Student(2,"lisi"));
                           hs.add(new Student(3,"wangwu"));
                           hs.add(new Student(1,"zhangsan"));
           
                           Iterator it=hs.iterator();
                           while(it.hasNext())
                           {
                                  System.out.println(it.next());
                           }
               }
          }
          class Student
             {
               int num;
               String name;
               Student(int num,String name)
                          {
                          this.num=num;
                           this.name=name;
                           }
                        public String toString()
                          {
                              return num+":"+name;
                           }
                     }     
          輸出結(jié)果為:
                                1:zhangsan
                             1:zhangsan
                             3:wangwu
                             2:lisi
          問題出現(xiàn)了,為什么hashset添加了相等的元素呢,這是不是和hashset的原則違背了呢?回答是:沒有
          因為在根據(jù)hashcode()對兩次建立的new Student(1,"zhangsan")對象進(jìn)行比較時,生成的是不同的哈希碼值,所以hashset把他當(dāng)作不同的對象對待了,當(dāng)然此時的 equals()方法返回的值也不等(這個不用解釋了吧)。那么為什么會生成不同的哈希碼值呢?上面我們在比較s1和s2的時候不是生成了同樣的哈希碼 嗎?原因就在于我們自己寫的Student類并沒有重新自己的hashcode()和equals()方法,所以在比較時,是繼承的object類中的 hashcode()方法,呵呵,各位還記得object類中的hashcode()方法比較的是什么吧!!
          它是一個本地方法,比較的是對象的地址(引用地址),使用new方法創(chuàng)建對象,兩次生成的當(dāng)然是不同的對象了(這個大家都能理解吧。。。),造成 的結(jié)果就是兩個對象的hashcode()返回的值不一樣。所以根據(jù)第一個準(zhǔn)則,hashset會把它們當(dāng)作不同的對象對待,自然也用不著第二個準(zhǔn)則進(jìn)行 判定了。那么怎么解決這個問題呢??
          答案是:在Student類中重新hashcode()和equals()方法。
          例如:
            class Student
          {
          int num;
          String name;
          Student(int num,String name)
          {
                      this.num=num;
                      this.name=name;
          }
          public int hashCode()
          {
                      return num*name.hashCode();
          }
          public boolean equals(Object o)
          {
                      Student s=(Student)o;
                      return num==s.num && name.equals(s.name);
          }
          public String toString()
          {
                      return num+":"+name;
          }
          }
          根據(jù)重寫的方法,即便兩次調(diào)用了new Student(1,"zhangsan"),我們在獲得對象的哈希碼時,根據(jù)重寫的方法hashcode(),獲得的哈希碼肯定是一樣的(這一點應(yīng)該沒有疑問吧)。
          當(dāng)然根據(jù)equals()方法我們也可判斷是相同的。所以在向hashset集合中添加時把它們當(dāng)作重復(fù)元素看待了。所以運行修改后的程序時,我們會發(fā)現(xiàn)運行結(jié)果是:
                                1:zhangsan
                             3:wangwu
                             2:lisi
          可以看到重復(fù)元素的問題已經(jīng)消除。
          關(guān)于在hibernate的pojo類中,重新equals()和hashcode()的問題:
          1),重點是equals,重寫hashCode只是技術(shù)要求(為了提高效率)
          2),為什么要重寫equals呢,因為在java的集合框架中,是通過equals來判斷兩個對象是否相等的
          3),在hibernate中,經(jīng)常使用set集合來保存相關(guān)對象,而set集合是不允許重復(fù)的。我們再來談?wù)勄懊嫣岬皆谙騢ashset集合中添加元素時,怎樣判斷對象是否相同的準(zhǔn)則,前面說了兩條,其實只要重寫equals()這一條也可以。
          但當(dāng)hashset中元素比較多時,或者是重寫的equals()方法比較復(fù)雜時,我們只用equals()方法進(jìn)行比較判斷,效率也會非常低, 所以引入了hashcode()這個方法,只是為了提高效率,但是我覺得這是非常有必要的(所以我們在前面以兩條準(zhǔn)則來進(jìn)行hashset的元素是否重復(fù) 的判斷)。
          比如可以這樣寫:
          public int hashCode(){
             return  1;}//等價于hashcode無效
          這樣做的效果就是在比較哈希碼的時候不能進(jìn)行判斷,因為每個對象返回的哈希碼都是1,每次都必須要經(jīng)過比較equals()方法后才能進(jìn)行判斷是否重復(fù),這當(dāng)然會引起效率的大大降低。
          我有一個問題,如果像前面提到的在hashset中判斷元素是否重復(fù)的必要方法是equals()方法(根據(jù)網(wǎng)上找到的觀點),但是這里并沒有涉及到關(guān)于哈希表的問題,可是這個集合卻叫hashset,這是為什么??
          我想,在hashmap,hashtable中的存儲操作,依然遵守上面的準(zhǔn)則。所以這里不再多說。這些是今天看書,網(wǎng)上查詢資料,自己總結(jié)出來 的,部分代碼和語言是引述,但是千真萬確是自己總結(jié)出來的。有錯誤之處和不詳細(xì)不清楚的地方還請大家指出,我也是初學(xué)者,所以難免會有錯誤的地方,希望大 家共同討論。
          posted @ 2011-05-27 18:15 redcoatjk 閱讀(371) | 評論 (0)編輯 收藏
          僅列出標(biāo)題
          共8頁: 上一頁 1 2 3 4 5 6 7 8 下一頁 
          CALENDER
          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          常用鏈接

          留言簿(3)

          隨筆分類(22)

          隨筆檔案(76)

          文章分類(12)

          文章檔案(17)

          搜索

          •  

          積分與排名

          • 積分 - 250885
          • 排名 - 227

          最新評論

          評論排行榜


          Powered By: 博客園
          模板提供滬江博客

          主站蜘蛛池模板: 双鸭山市| 江油市| 定边县| 崇明县| 西乌珠穆沁旗| 临澧县| 漳平市| 丹棱县| 手机| 巴楚县| 会泽县| 遵义县| 南宁市| 油尖旺区| 通州市| 汉沽区| 友谊县| 葵青区| 板桥市| 庄浪县| 马关县| 湖南省| 铁岭市| 汽车| 大英县| 林口县| 米易县| 新昌县| 宾阳县| 彭阳县| 平度市| 思茅市| 温宿县| 门头沟区| 保康县| 玉田县| 冀州市| 兴隆县| 大庆市| 抚宁县| 昌黎县|