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

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

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

    2008年1月10日

    MyEclipse使用技巧

    程序代碼自動(dòng)排版:Ctrl+Shift+F,會(huì)自動(dòng)把代碼進(jìn)行格式化的排版,非常方便
    快速執(zhí)行程序:Ctrl + F11第一次執(zhí)行時(shí),它會(huì)詢問您執(zhí)行模式,設(shè)置好后,以后只要按這個(gè)熱鍵,它就會(huì)快速執(zhí)行。

    Ctrl+Shift+/ 加上段注釋/**/

    Ctrl+Shift+\ 取消段注釋/**/

    Ctrl+/ 加上行注釋或取消行注釋

    自動(dòng)匯入所需要的類別:Ctrl+Shift+O

    取消自動(dòng)validation:
    取消方法: windows-->perferences-->myeclipse-->validation 
    除開Manual下面的復(fù)選框全部選中之外,其他全部不選 
    手工驗(yàn)證方法: 
    在要驗(yàn)證的文件上,單擊鼠標(biāo)右鍵-->myeclipse-->run validation 

    按new Remote Site,Name填 svn , URL填http://subclipse.tigris.org/update,一直next到finished為止

    posted @ 2008-02-18 21:09 靈! 閱讀(879) | 評(píng)論 (0)編輯 收藏

    幾個(gè)提高代碼質(zhì)量,檢查代碼規(guī)范的工具

    1.FindBugs:查錯(cuò)
     目前版本0.9.1,有for eclipse的插件. 網(wǎng)址是http://findbugs.sourceforge.net.
     
     工作原理:檢查程序生成的class的工具.
     
     界面:獨(dú)立運(yùn)行的提供圖形界面,很友好,有bug報(bào)告.
     
     可用性:大多數(shù)提示有用,值得改
     
     插件:
      可以設(shè)置基本和檢查的錯(cuò)誤類別.
      插件保存設(shè)置有問題,我是關(guān)閉項(xiàng)目后臺(tái)修改了配置文件,在裝入才成功改了配置的.
      bug臨時(shí)解決: 使用獨(dú)立的findbugs設(shè)置規(guī)則,然后到C:\Documents and Settings\XXX\下找.Findbugs_prefs,然后改名覆蓋eclipse project下的.fbprefs (先關(guān)閉你的project)
     
     配置沒有查找功能,不過縮寫能讓我們很快找到某個(gè)規(guī)則
     
    2.PMD:主要是查錯(cuò)
     目前版本3.2,有for eclipse以及其他ide的插件.網(wǎng)址是http://pmd.sourceforge.net
     工作原理:檢查源碼
     可用性:一部分值得修改,有些過于嚴(yán)格
     界面:獨(dú)立運(yùn)行的是命令行界面,命令比較簡(jiǎn)單.
     插件:可以配置規(guī)則,有一個(gè)獨(dú)立的窗口顯示提示,分5級(jí)提示,很友好
     
     使用:建立自己的規(guī)范,然后用于實(shí)際使用中.
     
    3.CheckStyle:主要查代碼規(guī)范
     目前版本4.0 beta 5,有for eclipse的插件.網(wǎng)址是http://checkstyle.sourceforge.net.
     工作原理:檢查源碼,對(duì)javadoc,書寫格式等進(jìn)行檢查.
     規(guī)則定義:默認(rèn)的規(guī)則是sun的編碼規(guī)范.不過按照sun的規(guī)則則過于嚴(yán)格,而且每個(gè)公司也有自己的規(guī)范,和sun的不同,所以需要自定義規(guī)范. 

    4.JTest 重量級(jí)的商業(yè)工具
     目前版本7.0.7,有for eclipse的插件.網(wǎng)址是http://www.parasoft.com/
     
     不推薦使用,不過功能強(qiáng)大,可以進(jìn)行代碼檢查,可以自動(dòng)生成單元測(cè)試和進(jìn)行單元測(cè)試.(不過就是太慢了,而且生成的單元測(cè)試沒太大用途)
     
     
     

    使用感覺:

     安裝上插件后,對(duì)自己的項(xiàng)目進(jìn)行檢查,發(fā)現(xiàn)警告太多了,有點(diǎn)發(fā)蒙的感覺.不過把警告看一遍,覺得都很有道理,有些也確實(shí)是一些錯(cuò)誤.
     當(dāng)然PMD和CheckStyle的規(guī)范太嚴(yán)格,最后還是配置了一下.
     
     通過改正警告,感覺還是不錯(cuò),至少可以說自己的代碼可以通過工具的檢測(cè)了.
     
     當(dāng)然基礎(chǔ)代碼和項(xiàng)目代碼還是不一樣的,基礎(chǔ)代碼往往比較復(fù)雜,所以和普通項(xiàng)目代碼的規(guī)范應(yīng)該有所不同.有些規(guī)則只能用在普通代碼上,用在基礎(chǔ)類代碼上往往沒法處理.
     
    其他

    代碼查錯(cuò)推薦使用Findbugs和PMD,代碼書寫規(guī)范推薦使用CheckStyle進(jìn)行檢查.這樣不僅能查出一些基本的錯(cuò)誤,也能提高項(xiàng)目的代碼質(zhì)量.對(duì)提高自己的代碼水平也是非常好.

    推薦項(xiàng)目組建立統(tǒng)一的規(guī)則,代碼復(fù)查的時(shí)候就使用這些工具,省時(shí)省力.

    實(shí)乃居家旅行,殺人越貨必備之工具也.(因?yàn)榭隙ㄓ腥艘R你,呵呵,也是你找"差"的工具)

    posted @ 2008-01-11 09:48 靈! 閱讀(916) | 評(píng)論 (0)編輯 收藏

    使用Lucene進(jìn)行全文檢索(一)---處理索引

     Lucene是一個(gè)全文檢索的引擎,目前有Java和.Net 等幾個(gè)版本.Java版本的網(wǎng)址是http://lucene.apache.org.相關(guān)的一個(gè)項(xiàng)目是車東的WebLucene: http://sourceforge.net/projects/weblucene.

     首先,基于一個(gè)簡(jiǎn)單的新聞系統(tǒng),要想做全文檢索.新聞系統(tǒng)的管理等在這里不在具體提出,下面列出新聞對(duì)象的類:
     
     注:程序用會(huì)到一些工具類,不在此列出,用戶可以自己實(shí)現(xiàn).
     
     

      package com.jscud.website.newsinfo.bean;
      
      
      import java.sql.Timestamp;
      
      import com.jscud.util.DateTime;
      import com.jscud.util.StringFunc;
      import com.jscud.website.newsinfo.NewsConst;
      
      
      /**
       * 一個(gè)新聞.
       *
       * @author scud(飛云小俠) http://www.jscud.com
       * 
       */
      public class NewsItem
      {
      
          private int nid; //新聞編號(hào)
      
          private int cid; //類別編號(hào)
      
          private String title;//標(biāo)題
      
          private int showtype; //內(nèi)容類型:目前支持url和html
      
          private String content;//內(nèi)容
      
          private String url;//對(duì)應(yīng)網(wǎng)址,如果內(nèi)容類型是url的話
      
          private Timestamp addtime; //增加時(shí)間
      
          private int click; //點(diǎn)擊數(shù)
         
          //對(duì)應(yīng)的get,set函數(shù),較多不在列出,可以使用工具生成
          //......
      
         
          /**
           * 按照類型格式化
           */
          public String getShowContent()
          {
              String sRes = content;
              if(showtype == NewsConst.ShowType_HTML)
              {
              }  
              return sRes;
          }
         
          public String getTarget()
          {
              if(showtype == NewsConst.ShowType_URL)
              {
                  return "_blank";
              }
              else
                  return "";       
          }
         
          /**
           * 靜態(tài)Html文件的路徑及其名字
           */
          public String getHtmlFileName()
          {
              int nYear = DateTime.getYear_Date(getAddtime());
              int nMonth =  DateTime.getMonth_Date(getAddtime());
                 
              String sGeneFileName =
                 "/news/" + getCid() + "/" + nYear + "/" + nMonth +"/" + getNid() + ".htm";
             
              return sGeneFileName;
          }
         
          /**
           * 靜態(tài)Html文件的路徑
           */
          public String getHtmlFilePath()
          {
              int nYear = DateTime.getYear_Date(getAddtime());
              int nMonth =  DateTime.getMonth_Date(getAddtime());
                 
              String sGeneFilePath =
                 getCid() + "_" + nYear + "_" + nMonth;
             
              return sGeneFilePath;
          }     
      } 


     
     可以看到,我們需要對(duì)標(biāo)題和內(nèi)容進(jìn)行檢索,為了這個(gè)目的,我們首先需要來研究一下lucene.
     
     在Lucene中,如果要進(jìn)行全文檢索,必須要先建立索引然后才能進(jìn)行檢索,當(dāng)然實(shí)際工作中還會(huì)有刪除索引和更新索引的工作.
     
     在此之前,介紹一個(gè)最基本的類(摘抄自http://www.tkk7.com/cap/archive/2005/07/17/7849.html):
     
     Analyzer 文件的分析器(聽起來別扭,還是叫Analyzer好了)的抽象,這個(gè)類用來處理分詞(對(duì)中文尤其重要,轉(zhuǎn)換大小寫(Computer->computer,實(shí)現(xiàn)查詢大小寫無關(guān)),轉(zhuǎn)換詞根(computers->computer),消除stop words等,還負(fù)責(zé)把其他格式文檔轉(zhuǎn)換為純文本等.
     
     在lucene中,一般會(huì)使用StandardAnalyzer來分析內(nèi)容,它支持中文等多字節(jié)語言,當(dāng)然可以自己實(shí)現(xiàn)特殊的解析器.StandardAnalyzer目前對(duì)中文的處理是按照單字來處理的,這是最簡(jiǎn)單的辦法,但是也有缺點(diǎn),會(huì)組合出一些沒有意義的結(jié)果來. 
     
     
     首先我們來了解建立索引,建立索引包含2種情況,一種是給一條新聞建立索引,另外的情況是在開始或者一定的時(shí)間給批量的新聞建立索引,所以為了通用,我們寫一個(gè)通用的建立索引的函數(shù):
     
     (一般一類的索引都放在一個(gè)目錄下,這個(gè)配置可以在函數(shù)中定義,也可以寫在配置文件中,通過參數(shù)傳遞給函數(shù).)

        /**
         * 生成索引.
         *
         * @param doc 目標(biāo)文檔
         * @param indexDir 索引目錄
         */
        public static void makeIndex(Document doc, String indexDir)
        {
            List aList = new ArrayList();
            aList.add(doc);
            makeIndex(aList, indexDir);
        }
     
        /**
         * 生成索引.
         *
         * @param doc 生成的document.
         * @param indexDir 索引目錄
         */
        public static void makeIndex(List docs, String indexDir)
        {
            if (null == docs)
            {
                return;
            }       
            boolean indexExist = indexExist(indexDir);

            IndexWriter writer = null;
            try
            {
                StandardAnalyzer analyzer = new StandardAnalyzer();
               
                //如果索引存在,就追加.如果不存在,就建立新的索引.lucene要是自動(dòng)判決就好了.
                if(indexExist)
                {
                    writer = new IndexWriter(indexDir, analyzer, false);
                }
                else
                {
                    writer = new IndexWriter(indexDir, analyzer, true);
                }

                //添加一條文檔
                for (int i = 0; i < docs.size(); i++)
                {
                    Document doc = (Document) docs.get(i);
                    if (null != doc)
                    {
                        writer.addDocument(doc);
                    }
                }

                //索引完成后的處理
                writer.optimize();
            }
            catch (IOException e)
            {
                LogMan.warn("Error in Make Index", e);
            }
            finally
            {
                try
                {
                    if (null != writer)
                    {
                        writer.close();
                    }
                }
                catch (IOException e)
                {
                    LogMan.warn("Close writer Error");
                }
            }
        }



     可以看到,建立索引用到類是IndexWrite,它可以新建索引或者追加索引,但是需要自己判斷.判斷是通過IndexReader這個(gè)類來實(shí)現(xiàn)的,函數(shù)如下:

     

      /**
         * 檢查索引是否存在.
         * @param indexDir
         * @return
         */
        public static boolean indexExist(String indexDir)
        {
            return IndexReader.indexExists(indexDir);
        }
     


     如果每次都是新建索引的話,會(huì)把原來的記錄刪除,我在使用的時(shí)候一開始就沒有注意到,后來觀察了一下索引文件,才發(fā)現(xiàn)這個(gè)問題.
     
     
     還可以看到,建立索引是給用戶的Document對(duì)象建立索引,Document表示索引中的一條文檔記錄.那么我們?nèi)绾谓⒁粋€(gè)文檔那?以新聞系統(tǒng)為例,代碼如下:
     

         /**
          * 生成新聞的Document.
          *
          * @param aNews 一條新聞.
          *
          * @return lucene的文檔對(duì)象
          */
         public static Document makeNewsSearchDocument(NewsItem aNews)
         {
             Document doc = new Document();
     
             doc.add(Field.Keyword("nid", String.valueOf(aNews.getNid())));
     
             doc.add(Field.Text("title", aNews.getTitle()));
            
             //對(duì)Html進(jìn)行解析,如果不是html,則不需要解析.或者根據(jù)格式調(diào)用自己的解析方法
             String content = parseHtmlContent(aNews.getContent());
     
             doc.add(Field.UnStored("content", content));
     
             doc.add(Field.Keyword("addtime", aNews.getAddtime()));
     
             //可以加入其他的內(nèi)容:例如新聞的評(píng)論等
             doc.add(Field.UnStored("other", ""));
     
             //訪問url
             String newsUrl = "/srun/news/viewhtml/" + aNews.getHtmlFilePath() + "/" + aNews.getNid()
                             + ".htm";
     
             doc.add(Field.UnIndexed("visiturl", newsUrl));
     
             return doc;
         }


     
     通過上面的代碼,我們把一條新聞轉(zhuǎn)換為lucene的Document對(duì)象,從而進(jìn)行索引工作.在上面的代碼中,我們又引入了lucene中的Field(字段)類.Document文檔就像數(shù)據(jù)庫(kù)中的一條記錄,它有很多字段,每個(gè)字段是一個(gè)Field對(duì)象.
     
     從別的文章摘抄一段關(guān)于Field的說明(摘抄自http://www.tkk7.com/cap/archive/2005/07/17/7849.html):
     [quote]
        類型                               Analyzed Indexed Stored 說明
        Field.Keyword(String,String/Date)  N Y Y                    這個(gè)Field用來儲(chǔ)存會(huì)直接用來檢索的比如(編號(hào),姓名,日期等)
        Field.UnIndexed(String,String)     N N Y                    不會(huì)用來檢索的信息,但是檢索后需要顯示的,比如,硬件序列號(hào),文檔的url地址
        Field.UnStored(String,String)      Y Y N                    大段文本內(nèi)容,會(huì)用來檢索,但是檢索后不需要從index中取內(nèi)容,可以根據(jù)url去load真實(shí)的內(nèi)容
        Field.Text(String,String)          Y Y Y                    檢索,獲取都需要的內(nèi)容,直接放index中,不過這樣會(huì)增大index
        Field.Text(String,Reader)          Y Y N                    如果是一個(gè)Reader, lucene猜測(cè)內(nèi)容比較多,會(huì)采用Unstored的策略.
     [/quote]
     
     我們可以看到新聞的編號(hào)是直接用來檢索的,所以是Keyword類型的字段,新聞的標(biāo)題是需要檢索和顯示用的,所以是Text類型,而新聞的內(nèi)容因?yàn)槭荋tml格式的,所以在經(jīng)過解析器的處理用,使用的UnStored的格式,而新聞的時(shí)間是直接用來檢索的,所以是KeyWord類型.為了在新聞索引后用戶可以訪問到完整的新聞頁面,還設(shè)置了一個(gè)UnIndexed類型的訪問地址字段.
     
     (對(duì)Html進(jìn)行解析的處理稍后在進(jìn)行講解)
     
     為一條新聞建立索引需要兩個(gè)步驟:獲取Document,傳給makeIndex函數(shù),代碼如下:

        public static void makeNewsInfoIndex(NewsItem aNews)
        {
            if (null == aNews)
            {
                return;
            }
            makeIndex(makeNewsSearchDocument(aNews),indexDir);
        }  


     

     
     
     建立索引的工作就進(jìn)行完了,只要在增加新聞后調(diào)用 makeNewsInfoIndex(newsitem); 就可以建立索引了.
     
     如果需要?jiǎng)h除新聞,那么也要?jiǎng)h除對(duì)應(yīng)的索引,刪除索引是通過IndexReader類來完成的:
     


        /**
         * 刪除索引.
         * @param aTerm 索引刪除條件
         * @param indexDir 索引目錄
         */
        public static void deleteIndex(Term aTerm, String indexDir)
        {
            List aList = new ArrayList();
            aList.add(aTerm);
            deleteIndex(aList, indexDir);
        }

        /**
         * 刪除索引.
         *
         * @param aTerm 索引刪除條件.
         * @param indexDir 索引目錄
         * 
         */
        public static void deleteIndex(List terms, String indexDir)
        {
            if (null == terms)
            {
                return;
            }
           
            if(!indexExist(indexDir)) { return; }

            IndexReader reader = null;
            try
            {
                reader = IndexReader.open(indexDir);
                for (int i = 0; i < terms.size(); i++)
                {
                    Term aTerm = (Term) terms.get(i);
                    if (null != aTerm)
                    {
                        reader.delete(aTerm);
                    }
                }
            }
            catch (IOException e)
            {
                LogMan.warn("Error in Delete Index", e);
            }
            finally
            {
                try
                {
                    if (null != reader)
                    {
                        reader.close();
                    }
                }
                catch (IOException e)
                {
                    LogMan.warn("Close reader Error");
                }
            }
        } 


     
     刪除索引需要一個(gè)條件,類似數(shù)據(jù)庫(kù)中的字段條件,例如刪除一條新聞的代碼如下:
     

         public static void deleteNewsInfoIndex(int nid)
         {
             Term aTerm = new Term("nid", String.valueOf(nid));
             deleteIndex(aTerm,indexDir);
         }   




     通過新聞的ID,就可以刪除一條新聞.
     
     如果需要更新新聞,如何更新索引哪? 更新索引需要先刪除索引然后新建索引2個(gè)步驟,其實(shí)就是把上面的代碼組合起來,例如更新一條新聞:

         public static void updateNewsInfoIndex(NewsItem aNews)
         {
             if (null == aNews)
             {
                 return;
             }
             deleteNewsInfoIndex(aNews.getNid());
             makeNewsInfoIndex(aNews);
         } 
     



     
     至此,索引的建立更新和刪除就告一段落了.其中批量更新新聞的代碼如下:
     (批量更新應(yīng)該在訪問人數(shù)少或者后臺(tái)程序在夜間執(zhí)行)

        public static void makeAllNewsInfoIndex(List newsList)
        {
            List terms = new ArrayList();
            List docs = new ArrayList();

            for (int i = 0; i < newsList.size(); i++)
            {
                NewsItem aitem = (NewsItem) newsList.get(i);
                if (null != aitem)
                {
                    terms.add(new Term("nid", String.valueOf(aitem.getNid())));
                    docs.add(makeNewsSearchDocument(aitem));
                }
            }

            deleteIndex(terms,indexDir);
            makeIndex(docs,indexDir);
        } 

    posted @ 2008-01-11 09:47 靈! 閱讀(385) | 評(píng)論 (0)編輯 收藏

    分析/解析Html頁面:HTML Parser的試用

    最近在研究lucene的全文檢索,在很多地方需要解析或者說分析Html內(nèi)容或者Html頁面,Lucene本身的演示程序中也提供了一個(gè)Html Parser,但是不是純Java的解決方案.于是到處搜索,在網(wǎng)上找到了一個(gè)"HTMLParser".

    網(wǎng)址是: http://htmlparser.sourceforge.net ,當(dāng)前版本為1.5.

    下載下來,試用一番,感覺不錯(cuò),完全能滿足lucene解析Html的需求.

    過幾天貼出lucene進(jìn)行全文檢索的代碼.(檢索本站的文章等).

    試用代碼如下,供大家參考:

    package com.jscud.test;

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStreamReader;

    import org.htmlparser.Node;
    import org.htmlparser.NodeFilter;
    import org.htmlparser.Parser;
    import org.htmlparser.filters.NodeClassFilter;
    import org.htmlparser.filters.OrFilter;
    import org.htmlparser.nodes.TextNode;
    import org.htmlparser.tags.LinkTag;
    import org.htmlparser.util.NodeList;
    import org.htmlparser.util.ParserException;
    import org.htmlparser.visitors.HtmlPage;
    import org.htmlparser.visitors.TextExtractingVisitor;

    import com.jscud.util.LogMan; //一個(gè)日志記錄類

    /**
     * 演示了Html Parse的應(yīng)用.
     *
     * @author scud http://www.jscud.com
     */

    public class ParseHtmlTest
    {

        public static void main(String[] args) throws Exception
        {
            String aFile = "e:/jscud/temp/test.htm";

            String content = readTextFile(aFile, "GBK");

            test1(content);
            System.out.println("====================================");

            test2(content);
            System.out.println("====================================");

            test3(content);
            System.out.println("====================================");

            test4(content);
            System.out.println("====================================");

            test5(aFile);
            System.out.println("====================================");

            //訪問外部資源,相對(duì)慢
            test5("         System.out.println("====================================");

        }

        /**
         * 讀取文件的方式來分析內(nèi)容.
         * filePath也可以是一個(gè)Url.
         *
         * @param resource 文件/Url
         */
        public static void test5(String resource) throws Exception
        {
            Parser myParser = new Parser(resource);

            //設(shè)置編碼
            myParser.setEncoding("GBK");

            HtmlPage visitor = new HtmlPage(myParser);

            myParser.visitAllNodesWith(visitor);

            String textInPage = visitor.getTitle();

            System.out.println(textInPage);
        }

        /**
         * 按頁面方式處理.對(duì)一個(gè)標(biāo)準(zhǔn)的Html頁面,推薦使用此種方式.
         */
        public static void test4(String content) throws Exception
        {
            Parser myParser;
            myParser = Parser.createParser(content, "GBK");

            HtmlPage visitor = new HtmlPage(myParser);

            myParser.visitAllNodesWith(visitor);

            String textInPage = visitor.getTitle();

            System.out.println(textInPage);
        }

        /**
         * 利用Visitor模式解析html頁面.
         *
         * 小優(yōu)點(diǎn):翻譯了<>等符號(hào)
         * 缺點(diǎn):好多空格,無法提取link
         *  
         */
        public static void test3(String content) throws Exception
        {
            Parser myParser;
            myParser = Parser.createParser(content, "GBK");

            TextExtractingVisitor visitor = new TextExtractingVisitor();

            myParser.visitAllNodesWith(visitor);

            String textInPage = visitor.getExtractedText();

            System.out.println(textInPage);
        }

        /**
         * 得到普通文本和鏈接的內(nèi)容.
         *
         * 使用了過濾條件.
         */
        public static void test2(String content) throws ParserException
        {
            Parser myParser;
            NodeList nodeList = null;

            myParser = Parser.createParser(content, "GBK");

            NodeFilter textFilter = new NodeClassFilter(TextNode.class);
            NodeFilter linkFilter = new NodeClassFilter(LinkTag.class);

            //暫時(shí)不處理 meta
            //NodeFilter metaFilter = new NodeClassFilter(MetaTag.class);

            OrFilter lastFilter = new OrFilter();
            lastFilter.setPredicates(new NodeFilter[] { textFilter, linkFilter });

            nodeList = myParser.parse(lastFilter);

            Node[] nodes = nodeList.toNodeArray();

            for (int i = 0; i < nodes.length; i++)
            {
                Node anode = (Node) nodes[i];

                String line = "";
                if (anode instanceof TextNode)
                {
                    TextNode textnode = (TextNode) anode;
                    //line = textnode.toPlainTextString().trim();
                    line = textnode.getText();
                }
                else if (anode instanceof LinkTag)
                {
                    LinkTag linknode = (LinkTag) anode;

                    line = linknode.getLink();
                   
    //@todo 過濾jsp標(biāo)簽:可以自己實(shí)現(xiàn)這個(gè)函數(shù)
                    //line = StringFunc.replace(line, "<%.*%>", "");
                }

                if (isTrimEmpty(line))
                    continue;

                System.out.println(line);
            }
        }

        /**
         * 解析普通文本節(jié)點(diǎn).
         *
         * @param content
         * @throws ParserException
         */
        public static void test1(String content) throws ParserException
        {
            Parser myParser;
            Node[] nodes = null;

            myParser = Parser.createParser(content, null);

            nodes = myParser.extractAllNodesThatAre(TextNode.class); //exception could be thrown here

            for (int i = 0; i < nodes.length; i++)
            {
                TextNode textnode = (TextNode) nodes[i];
                String line = textnode.toPlainTextString().trim();
                if (line.equals(""))
                    continue;
                System.out.println(line);
            }

        }

        /**
         * 讀取一個(gè)文件到字符串里.
         *
         * @param sFileName  文件名
         * @param sEncode   String
         * @return 文件內(nèi)容
         */
        public static String readTextFile(String sFileName, String sEncode)
        {
            StringBuffer sbStr = new StringBuffer();

            try
            {
                File ff = new File(sFileName);
                InputStreamReader read = new InputStreamReader(new FileInputStream(ff),
                        sEncode);
                BufferedReader ins = new BufferedReader(read);

                String dataLine = "";
                while (null != (dataLine = ins.readLine()))
                {
                    sbStr.append(dataLine);
                    sbStr.append("\r\n");
                }

                ins.close();
            }
            catch (Exception e)
            {
                LogMan.error("read Text File Error", e);
            }

            return sbStr.toString();
        }

        /**
         * 去掉左右空格后字符串是否為空
         * @param astr String
         * @return boolean
         */
        public static boolean isTrimEmpty(String astr)
        {
            if ((null == astr) || (astr.length() == 0))
            {
                return true;
            }
            if (isBlank(astr.trim()))
            {
                return true;
            }
            return false;
        }

        /**
         * 字符串是否為空:null或者長(zhǎng)度為0.
         * @param astr 源字符串.
         * @return boolean
         */
        public static boolean isBlank(String astr)
        {
            if ((null == astr) || (astr.length() == 0))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

    }

     


    posted @ 2008-01-11 09:45 靈! 閱讀(350) | 評(píng)論 (0)編輯 收藏

    JavaEE事務(wù)掃盲筆記之一掃掃到尾

    1.資料

    2.本地事務(wù)與分布式事務(wù)

    • 本地事務(wù)
      完全依賴于DB、JMS自身,,如直接調(diào)用jdbc中的conn.commit();這里沒應(yīng)用服務(wù)器什么事,所以也不支持多數(shù)據(jù)源的全局事務(wù)。
    • 分布式事務(wù)
      在JavaEE世界的事務(wù)在JTA、JTS規(guī)范和XA Sources之上實(shí)現(xiàn)。
      JTA是用戶編程接口,JTS是服務(wù)器底層服務(wù),兩者一般由應(yīng)用服務(wù)器自帶實(shí)現(xiàn),而atomikos 、JOTM 和JBoss Transaction 是專門搞局搶生意的。
      XA Sources其實(shí)先于JavaEE而存在,JDBC driver必須有javax.sql.XADataSource接口的實(shí)現(xiàn)類,否則所謂二階段提交就是個(gè)偽能力。
      JavaEE除了支持JDBC和JMS外,還引入了JCA模型。JCA可以說是目前唯一可移植的插入JavaEE事務(wù)的資源模型,因此像JDO這類框架/Server就是靠乖乖出自己的JCA連接器來參與JavaEE事務(wù)的。

    3.編程式模型

        手工調(diào)用jdbc的connection事務(wù)方法和使用JTA接口都屬于編程式開發(fā),在EJB中叫BMT(Bean管理事務(wù))。
        JTA最重要的接口就是UserTransaction和它的六個(gè)方法-begin,commit,rollback,getStatus,setRollbackonly,setTransactionTimeout。
        程序需要UserTransaction時(shí)可以從JNDI領(lǐng)取,不過JNDI名隨應(yīng)用服務(wù)器不同而不同。EJB3里可以直接用個(gè)@Resource注入。

    4.宣告式模型

        前面都是鋪墊,這個(gè)才是主打的事務(wù)模型,如EJB的CMT(容器管理事務(wù))和Sprin。

        其中EJB2.0,Spring1.0在部署描述符和applicationContext.xml中定義,而EJB3.0和Spring2.0則采用annotation。

    4.1 事務(wù)類型

         這里JavaEE與Spring的定義基本相同:

    • Required:如果Context中有事務(wù)就加入,沒有就自己創(chuàng)建一個(gè)。(最常用設(shè)置)
    • Mandatory:永遠(yuǎn)加入一個(gè)事務(wù)。如果當(dāng)前Context沒有事務(wù),拋出異常。(那些不打算自己負(fù)責(zé)rollback事務(wù)的方法,必須加入到別人的事務(wù),由別人來控制rollback)
    • RequiresNew:永遠(yuǎn)新建一個(gè)事務(wù)。(那些不管別人如何,自己必須提交事務(wù)的方法,比如審計(jì)信息是一定要寫的)
    • Supports:如果有事務(wù)就加入,如果沒有就算了。永遠(yuǎn)不會(huì)創(chuàng)建新事務(wù)。(一般用于只讀方法,不會(huì)主動(dòng)創(chuàng)建事務(wù),但如果當(dāng)前有事務(wù)就加入,以讀到事務(wù)中未提交的數(shù)據(jù))
    • NotSupported:永遠(yuǎn)不使用事務(wù),如果當(dāng)前有事務(wù),掛起事務(wù)。(那些有可能拋異常但異常并不影響全局的方法)
    • Never:不能在有當(dāng)前事務(wù)的情況下調(diào)用本方法。(生人勿近?)

          可見,Required是默認(rèn)的設(shè)置,Supports是只讀方法的最佳選擇。

    4.2 事務(wù)隔離級(jí)別

    • ReadUncommited:本事務(wù)可以看到另一事務(wù)未提交的數(shù)據(jù)。臟讀。
    • ReadCommited:本事務(wù)只可以看到另一事務(wù)已提交的數(shù)據(jù)。不可重復(fù)讀。
    • RepeatableRead:可重復(fù)讀。在一個(gè)事務(wù)內(nèi),第一次讀到的數(shù)據(jù),在本事務(wù)沒有提交前,無論另一個(gè)事務(wù)如何提交數(shù)據(jù),本事務(wù)讀到的數(shù)據(jù)都是不變的。
    • Serializable:串行化,同時(shí)只有一個(gè)事務(wù)能讀相同的數(shù)據(jù)。

        級(jí)別越低越安全效率也越低。隔離級(jí)別需要相關(guān)資源支持,如重復(fù)讀在Oracle里會(huì)降級(jí)為ReadCommited。Spring里默認(rèn)的Default級(jí)別完全看數(shù)據(jù)源的臉色行事。

    4.3 關(guān)于Rollback

        EJB里,想rollback只能sessionContext.setRollbackOnly(),或者拋出EJBException。(EJB3還可以annotation設(shè)置某些自定義Exception可以觸發(fā)rollback)

        在Spring里,同樣只會(huì)rollback unchecked exception(RuntimeExcption及子類),而checked exception(Exception及子類)是不會(huì)rollback的,除非你特別聲明。

       @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW,rollbackFor = {MyException1.class,MyException2.class})

        因此所有在service層方法中用throws定義的Exception,都必須在事務(wù)定義中進(jìn)行rollback設(shè)定。(請(qǐng)勿善忘)

        所有在service層方法中c被atch處理了的異常,又希望容器輔助rollback的話,必須重拋一個(gè)預(yù)定義的RuntimeException的子類。(請(qǐng)勿回望)

    4.4 關(guān)于Spring

        Spring不希望編程式事務(wù)管理。
        Spring也不希望使用EJB CMT--CMT依賴于EJB而無法用于POJO,依賴于JTA全局事務(wù)對(duì)單數(shù)據(jù)源場(chǎng)景造成了浪費(fèi),而且rollback機(jī)制比較麻煩(必須為EJBException或手工setRollbackOnly())。
        因此Spring通過AOP實(shí)現(xiàn)了對(duì)POJO的整套宣告式事務(wù)體系;對(duì)jdbc,hibernate,jpa,jms等local數(shù)據(jù)源和JTA實(shí)現(xiàn)了統(tǒng)一的事務(wù)管理機(jī)制,而且支持本地資源與JTA在配置文件級(jí)的切換,而且改進(jìn)了rollback機(jī)制。

       1)一個(gè)本地事務(wù)管理器:

    <bean id="transactionManager"  class="org.springframework.orm.jpa.JpaTransactionManager">  <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean>

       2)Spring就會(huì)把請(qǐng)求都轉(zhuǎn)發(fā)到應(yīng)用服務(wù)器的JTA對(duì)象上(注意此時(shí)數(shù)據(jù)源也需要改為用JNDI從應(yīng)用服務(wù)器獲取)。

    <bean id="myTxManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>

       3)應(yīng)用服務(wù)器專有的類型的JTA事務(wù)管理器:

    <bean id="myTxManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager"/>

    posted @ 2008-01-11 09:44 靈! 閱讀(379) | 評(píng)論 (0)編輯 收藏

    包裝你的Session,使Session對(duì)象化

     在Web開發(fā)中,經(jīng)常需要使用Session來保存特定用戶的信息,在我們的程序中很多地方散落著類似下面的語句:
     int userAge = (int)this.Session["UserAge"];
        
        我們知道,Session中存放的是鍵值對(duì),鍵是string類型的,如果我們一不小心把上面的語句寫成這樣:
      int userAge = (int)this.Session["UseAge"];
        編譯期不會(huì)發(fā)現(xiàn)這個(gè)錯(cuò)誤,但運(yùn)行時(shí)一定會(huì)拋出異常,這是在程序中直接操作Session可能引發(fā)的問題之一。另外,每次獲取userAge的時(shí)候都要寫代碼進(jìn)行強(qiáng)制轉(zhuǎn)換,感覺很繁瑣。我們需要一個(gè)解決方案來解決這些問題。我的做法是引入一個(gè)Session的包裝,使之對(duì)象化、強(qiáng)類型化。就像接下來的例子一樣:
    public class SessionHelper
    {
        
    private HttpSessionState curSession;

        
    public SessionHelper(HttpSessionState session)
        {
            
    this.curSession = session;
        }

        
    public static SessionHelper CreateInstance(HttpSessionState session)
        {        
            
    return new SessionHelper(session);
        }


        
    public string UserID
        {
            
    get
            {
                
    return this.curSession["UserID"].ToString();
            }
            
    set
            {
                
    this.curSession["UserID"= value ;
            }
        }

        
    public int UserAge
        {
            
    get
            {
                
    return (int)this.curSession["UserAge"];
            }
            
    set
            {
                
    this.curSession["UserAge"= value ;
            }
        }

        
    //某用戶上傳的所有圖片
        public ArrayList PicList
        {
            
    get
            {
                
    if (this.curSession["PicList"== null)
                {
                    
    this.curSession["PicList"= new ArrayList();
                }

                
    return (ArraayList)this.curSession["PicList"];
            }       
        }

        
    //清空?qǐng)D片列表
        public void ClearAllPics()
        {
            
    this.PicList.Clear();
        }  
    }

        這樣,我們用起來就非常方便了:
           SessionHelper sessionHelper = SessionHelper.CreateInstance(this.Session);
            ArrayList picList 
    = sessionHelper.PicList;
            
    //    處理picList中的圖片
            sessionHelper.ClearAllPics();  

        引入這一層包裝,可以使我們的程序的可讀性、可維護(hù)性更好,而且將原來的一些運(yùn)行期的錯(cuò)誤提前到了編譯期,這也是強(qiáng)類型帶來的好處。

    posted @ 2008-01-11 09:36 靈! 閱讀(273) | 評(píng)論 (0)編輯 收藏

    Java -- 在Eclipse上使用Hibernate

      最近一個(gè)項(xiàng)目要用Java做,一點(diǎn)都不熟啊。沒辦法,只好硬著頭皮啃了,花了大半天的時(shí)間,終于在Eclipse上完成了第一個(gè)Hibernate例子。下面記錄關(guān)鍵的步驟,權(quán)作筆記,以備日后查看。

     (1)下載Hibernate,并向項(xiàng)目中導(dǎo)入Hibernate。
         Project->Properies->Java Build Path->Libraries->Add External JARs...,選擇Hibernate根目錄下的hibernate3.jar,添加到項(xiàng)目中。
        接著,要將Hibernate下的lib文件夾下的所有文件都作為一個(gè)User Library添加到項(xiàng)目中,否則,如果僅僅添加hibernate3.jar,編譯可以通過,運(yùn)行卻會(huì)拋出ClassNotDef的異常,因?yàn)閔ibernate3.jar依賴于Hibernate下的lib文件夾下的文件。

     2)我們的應(yīng)用的后臺(tái)數(shù)據(jù)庫(kù)使用的是Oracle,所以首先要在例子項(xiàng)目中引入含有Oracle jdbc driver的包,classes12.jar。該jar文件位于oracle安裝目錄的jdbc\lib目錄下。
        在Eclipse中,Project->Properies->Java Build Path->Libraries->Add External JARs...,選擇classes12.jar,將其添加到項(xiàng)目中。
        
    (3)生成hibernate.cfg.xml文件。
        通常Hibernate的配置文件和.hbm.xml文件都可以自動(dòng)生成,這種自動(dòng)生成的工具很多,我使用的是HibernateSynchronizer,它可以作為一個(gè)插件添加到Eclipse中。當(dāng)HibernateSynchronizer插件正確加載后,我們可以向當(dāng)前項(xiàng)目中添加Hibernate配置文件:File->New->Other->Hibernate->Hibernate Configuration File,出現(xiàn)如下界面:


      注意,Driver Class要選擇針對(duì)Oracle的oracle.jdbc.driver.OracleDriver,而且Database URL的格式也要正確,如:
    jdbc:oracle:thin:@10.8.8.221:1521:ORCL

        最好將hibernate.cfg.xml文件存放于項(xiàng)目的根目錄下。

     4)生成.hbm.xml文件。File->New->Other->Hibernate->Hibernate Mapping File,出現(xiàn)如下界面:

         
        在填寫完P(guān)assword后,點(diǎn)擊Refresh按鈕,就會(huì)在Tables中列出所有可以訪問的數(shù)據(jù)庫(kù)表,然后選中要為其生成.hbm.xml文件的表,點(diǎn)擊Finish,即會(huì)生成對(duì)應(yīng)的.hbm.xml文件,比如我上面選擇的是Mobileuser表,就會(huì)生成Mobileuser.hbm.xml文件。

    (5)從.hbm.xml文件自動(dòng)生成實(shí)體類。
        在Package Explorer中選中Mobileuser.hbm.xml文件,右鍵->Hibernate Synchronizer->Synchronize Files ,即可生成對(duì)應(yīng)的實(shí)體類和DAO類。如果你僅僅想要實(shí)體類,那么可以在Project->Properies->Hibernate Synchronizer->Data Access Objects ,將“I would like to have DAOs created for me”的鉤選項(xiàng)去掉即可。

    (6)在hibernate.cfg.xml文件中添加對(duì)應(yīng)的mapping resource。
        在Package Explorer中選中Mobileuser.hbm.xml文件,右鍵->Hibernate Synchronizer->Add Mapping Reference,即會(huì)在
    hibernate.cfg.xml中自動(dòng)生成如下配置:

    <mapping resource="HibernateTest/Mobileuser.hbm.xml" />

    (7)修改自動(dòng)生成的hibernate.cfg.xml文件。需要在hibernate.cfg.xml文件的首部添加:

    <!DOCTYPE hibernate-configuration PUBLIC
            
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
            
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

        比較繁瑣的是,每次自動(dòng)修改hibernate.cfg.xml文件后,都要重新添加這個(gè)xml片斷。

        萬事具備,現(xiàn)在可以寫個(gè)測(cè)試來檢驗(yàn)一下了:

        //僅僅作為示例,沒有進(jìn)行異常處理
        public static void main(String[] args)
        {
            Configuration cfg 
    = new Configuration().configure() ;        
            SessionFactory  sFactory 
    = cfg.buildSessionFactory() ;        
            
            Session session 
    = sFactory.openSession() ;
            Transaction tx 
    = session.beginTransaction();
            Mobileuser user 
    = (Mobileuser)session.load(Mobileuser.class , new Integer(2)) ;
            String age 
    = user.getMobilenumber() ;
            
            System.
    out.println(age) ;
            tx.commit();
            session.close() ;
        }

    posted @ 2008-01-11 09:34 靈! 閱讀(612) | 評(píng)論 (0)編輯 收藏

    Java -- 在Eclipse上使用Spring

       在.NET上用的VS.NET+Spring.net+Nhibernate,到了Java平臺(tái)上,自然對(duì)應(yīng)著Eclipse+Spring+Hibernate。上一篇文章介紹了如何在Eclipse上使用Hibernate的入門,本文就簡(jiǎn)單介紹一下如何在Eclipse使用Spring。

        (1)首先,是下載Spring,可以從sourceforge上下載,http://sourceforge.net/projects/springframework。目前的最新的可以下載 spring-framework-1.2.8-with-dependencies.zip 。

        (2)然后,可以將Spring引入到你的項(xiàng)目中。
        先將spring-framework-1.2.8-with-dependencies.zip解壓,將其中的spring.jar(dist目錄中)、commons-logging.jar(lib\jakarta-commons目錄)、log4j-1.2.13.jar(lib\log4j目錄)這三個(gè)文件復(fù)制到的”D:\java\Spring\lib" 目錄中,然后在Eclipse中建立一個(gè)“Spring”庫(kù),將那三個(gè)文件添加進(jìn)“Spring”庫(kù)中。

        (3)測(cè)試一下:
        新建兩個(gè)類,Student和Book。
    public class Book 
    {
        
    private int id = 0 ;
        
    private String bookName ;
        
    public String getBookName() {
            
    return bookName;
        }
        
    public void setBookName(String bookName) {
            
    this.bookName = bookName;
        }
        
    public int getId() {
            
    return id;
        }
        
    public void setId(int id) {
            
    this.id = id;
        }
    }

    public class Student 
    {
        
    private int age = 0;    
        
    private String name ;
        
    private Book book ;

        
    public int getAge() {
            
    return age;
        }

        
    public void setAge(int age) {
            
    this.age = age;
        }
        
        
    public String getName() {
            
    return name;
        }

        
    public void setName(String name) {
            
    this.name = name;
        }

        
    public Book getBook() {
            
    return book;
        }

        
    public void setBook(Book book) {
            
    this.book = book;
        }
        
        
    public String GetBookName()
        {
            
    return this.book.getBookName() ;
        }    
    }

        然后添加Spring配置文件bean.xml(bean.xml必須在CLASSPATH可以存取到的目錄中):
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" 
    "http://www.springframework.org/dtd/spring-beans.dtd">

    <beans>
        
    <bean id="student" class="com.springTest.Student">
            
    <property name="age">
                
    <value>22</value>
            
    </property>
            
    <property name="name">
                
    <value>Sky</value>
            
    </property>
            
    <property name="book" ref="book">            
            
    </property>
        
    </bean>
        
        
    <bean id="book" class="com.springTest.Book">
             
    <property name="id">
                
    <value>1000</value>
            
    </property>
            
    <property name="bookName">
                
    <value>戰(zhàn)爭(zhēng)與和平</value>
            
    </property>
        
    </bean>
    </beans>

        最后的主程序:
        public static void main(String[] args) 
        {
            Resource res 
    = new ClassPathResource("bean.xml");
            BeanFactory factory 
    = new XmlBeanFactory(res);

            Student stu 
    = (Student) factory.getBean("student");
            System.
    out.println(stu.GetBookName());
        }
        運(yùn)行后可以看到控制臺(tái)輸出--“戰(zhàn)爭(zhēng)與和平”。

        與Spring.net的使用基本完全一致(包括配置文件、BeanFactory的獲取等),所以熟悉Spring.net的你過渡到Spring是非常平滑的。
        最后,Java中的屬性實(shí)在是沒有C#中的簡(jiǎn)潔,呵呵。

    posted @ 2008-01-11 09:33 靈! 閱讀(361) | 評(píng)論 (0)編輯 收藏

    Java -- 在Eclipse上使用XFire開發(fā)WebService

       終于,使用Java完成了一個(gè)WebService的例子,其中的一個(gè)非常小的問題,折騰了我將近一天的時(shí)間。下面給出步驟,說明在Java平臺(tái)上如何開發(fā)WebService。

        采用的工具:Eclipse3.1.2 + Tomcat5.5 + XFire1.1 。使用XFire開發(fā)WebService應(yīng)該說非常的容易,只需要按照下面例子的步驟來做:

    (1)在Eclipse中新建一個(gè)dynamic Web Project ,假設(shè)名為XFireZhuweiTest。

    (2)導(dǎo)入XFire用戶庫(kù)。該庫(kù)中應(yīng)包含xfire-1.1目錄下的xfire-all-1.1.jar文件,以及xfire-1.1\lib目錄下的所有文件。

    (3)將上述的XFire用戶庫(kù)中的所有文件拷貝到XFireZhuweiTest項(xiàng)目的WebContent\WEB-INF\lib目錄下。

    (4)修改WebContent\WEB-INF\web.xml配置文件的內(nèi)容,下面是修改后web.xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
        <display-name>
        XFireZhuweiTest</display-name>
        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
            <welcome-file>index.htm</welcome-file>
            <welcome-file>index.jsp</welcome-file>
            <welcome-file>default.html</welcome-file>
            <welcome-file>default.htm</welcome-file>
            <welcome-file>default.jsp</welcome-file>
        </welcome-file-list>
        
        <servlet>
             <servlet-name>XFireServlet</servlet-name>
             <servlet-class>
                     org.codehaus.xfire.transport.http.XFireConfigurableServlet
             </servlet-class>
         </servlet>
         
         <servlet-mapping>
             <servlet-name>XFireServlet</servlet-name>
             <url-pattern>/servlet/XFireServlet/*</url-pattern>
         </servlet-mapping>
     
         <servlet-mapping>
             <servlet-name>XFireServlet</servlet-name>
              <url-pattern>/services/*</url-pattern>
         </servlet-mapping>
        
    </web-app>

        web.xml中添加的servlet映射表明,所有匹配“/services/*”的url請(qǐng)求全部交給org.codehaus.xfire.transport.http.XFireConfigurableServlet來處理。

    (5)編寫需要發(fā)布為WebService的Java類,這個(gè)例子中是一個(gè)非常簡(jiǎn)單的MathService.java。

    package com.zhuweisky.xfireDemo;
    public class MathService 
    {
        
    public int Add(int a ,int b)
        {
            
    return a+b ;
        }
    }

    (6)在WebContent\META-INF目錄下新建xfire文件夾,然后在xfire目錄下添加一個(gè)XFire使用的配置文件services.xml,該配置文件中的內(nèi)容反映了要將哪些java類發(fā)布為web服務(wù)。本例中的services.xml內(nèi)容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://xfire.codehaus.org/config/1.0">
        
    <service>
          
    <name>MathService</name>
          
    <namespace>http://com.zhuweisky.xfireDemo/MathService</namespace>
          <serviceClass>com.zhuweisky.xfireDemo.MathService</serviceClass>
        
    </service>
    </beans>

        XFire會(huì)借助Spring來解析services.xml,從中提取需要發(fā)布為WebService的配置信息。

        很多文章介紹到這里就完了,然而當(dāng)我按照他們所說的啟動(dòng)WebService ,然后通過http://localhost:8080/XFireZhuweiTest/services/MathService?wsdl 來訪問服務(wù)描述時(shí),卻拋出了異常,說services.xml文件不存在--
    “org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [META-INF/xfire/services.xml]; nested exception is java.io.FileNotFoundException: class path resource [META-INF/xfire/services.xml] cannot be opened because it does not exist”。  

    (7)非常關(guān)鍵的一點(diǎn),就是這個(gè)小難題花費(fèi)了我將近一天的時(shí)間。
        在WebContent\WEB-INF目錄下新建classes文件夾,然后需要將WebContent下的整個(gè)META-INF文件夾剪切到新建的classes文件夾下。
        到這里,項(xiàng)目的完整目錄結(jié)構(gòu)如下:



    (8)在Package Explorer中選中XFireZhuweiTest項(xiàng)目,右鍵->Run As ->Run On Server,關(guān)聯(lián)到你機(jī)器上的TomCat,然后會(huì)啟動(dòng)Tomcat,以啟動(dòng)web服務(wù)。(注意,在進(jìn)行此步驟之前,請(qǐng)先停止TomCat) 

    (9)在IE中輸入 http://localhost:8080/XFireZhuweiTest/services/MathService?wsdl 會(huì)得到正確的web服務(wù)描述文檔。

    (10)測(cè)試剛發(fā)布的webService。我使用C#動(dòng)態(tài)調(diào)用Web服務(wù):

                    //C#
                    string url = "http://localhost:8080/XFireZhuweiTest/services/MathService" ;
                    
    object[] args ={1,2} ;
                    
    object result = ESFramework.WebService.WebServiceHelper.InvokeWebService(url ,"Add" ,args) ;
                    MessageBox.Show(result.ToString());

        (關(guān)于C#動(dòng)態(tài)調(diào)用Web服務(wù),請(qǐng)參見這里

        執(zhí)行后,彈出對(duì)話框,顯示結(jié)果是3。

    posted @ 2008-01-11 09:31 靈! 閱讀(1807) | 評(píng)論 (0)編輯 收藏

    通用分頁存儲(chǔ)過程(原創(chuàng))

     這是我項(xiàng)目中使用的一個(gè)分頁存儲(chǔ)過程,具有很強(qiáng)的通用性。配合前臺(tái)ASP.NET使用50萬條數(shù)據(jù)基本感不到延遲。數(shù)據(jù)庫(kù)為SQLServer2000。

    1.分頁存儲(chǔ)過程

    CREATE   procedure pagination

     @str_sql           varchar(1000) = '*',     -- 執(zhí)行的SQL 不含Order by 內(nèi)容  
     @str_orderfield    varchar(255)='''',       -- 排序的字段名 
     @page_size         int = 10,                     -- 頁大小 
     @page_index        int = 0,                      -- 頁碼
     @order_type        int,                           -- 設(shè)置排序類型, 非 -1 值則降序 
     @total_count       int   output                 -- 返回記錄總數(shù), 非 0 值則返回 
    as

    ---------------------
    -- 獲取指定頁的數(shù)據(jù)--
    ---------------------

    declare @strsql   varchar(5000)              -- 主語句
    declare @strtmp   varchar(5000)             -- 臨時(shí)變量
    declare @strorder varchar(400)              -- 排序字串
    declare @cruRow   int                            -- 當(dāng)前行號(hào)
     

    --執(zhí)行總數(shù)統(tǒng)計(jì)
    exec getRowCount @str_sql,@total_count output

    set @strtmp =  ' select * from ' +
            '      (select top ' + convert(varchar(10),@page_size) + ' * from ' +
            '         (select top ' + convert(varchar(10),(@page_index + 1) * @page_size)  +' * from '+        -- N+1頁
            '            ('+ @str_sql +') Src '

    --排序方向
    if @order_type !=0
     begin
     set @strsql= @strtmp +
           '          order by @str_orderfield asc) a ' +
           '       order by @str_orderfield desc)b' +
                  ' order by @str_orderfield asc'
     end
    else
     begin
     set @strsql= @strtmp +
           '          order by @str_orderfield desc) a ' +
           '       order by  @str_orderfieldasc)b' +
                  ' order by  @str_orderfield desc'
     end

    exec (@strsql)

    GO

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

    2.分頁存儲(chǔ)過程執(zhí)行中用到的行數(shù)統(tǒng)計(jì)

    create  procedure getRowCount
           @sql    nvarchar(2000),
           @count  int output
    as
    begin

    --------------------
    -- 獲取數(shù)據(jù)總行數(shù) --
    --------------------

      declare @tmpsql nvarchar(2000)
      set @tmpsql='select @count=count(*)  from ('+ @sql +') a'

      execute sp_executesql @tmpsql,N'@count int output',@count output
     
    end

    GO

    posted @ 2008-01-10 17:08 靈! 閱讀(513) | 評(píng)論 (0)編輯 收藏

    JAVA面試題匯總 四

    31 構(gòu)造器Constructor是否可被override?

      構(gòu)造器Constructor不能被繼承,因此不能重寫Overriding,但可以被重載Overloading。

    32 是否可以繼承String類?

      String類是final類故不可以繼承。

    33 當(dāng)一個(gè)線程進(jìn)入一個(gè)對(duì)象的一個(gè)synchronized方法后,其它線程是否可進(jìn)入此對(duì)象的其它方法?

      不能,一個(gè)對(duì)象的一個(gè)synchronized方法只能由一個(gè)線程訪問。

    33  try {}里有一個(gè)return語句,那么緊跟在這個(gè)try后的finally {}里的code會(huì)不

    會(huì)被執(zhí)行,什么時(shí)候被執(zhí)行,在return前還是后? 
      會(huì)執(zhí)行,在return前執(zhí)行。

    34 編程題: 用最有效率的方法算出2乘以8等於幾? 

      2 << 3 

    35 兩個(gè)對(duì)象值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對(duì)不對(duì)?

      不對(duì),有相同的hash code。

    36  當(dāng)一個(gè)對(duì)象被當(dāng)作參數(shù)傳遞到一個(gè)方法后,此方法可改變這個(gè)對(duì)象的屬性,并可返回變化后的結(jié)果,那么這里到底是值傳遞還是引用傳遞?

      是值傳遞。Java編程語言只由值傳遞參數(shù)。當(dāng)一個(gè)對(duì)象實(shí)例作為一個(gè)參數(shù)被傳遞到方法中時(shí),參數(shù)的值就是對(duì)該對(duì)象的引用。對(duì)象的內(nèi)容可以在被調(diào)用的方法中改變,但對(duì)象的引用是永遠(yuǎn)不會(huì)改變的。

    37  swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?

      switch(expr1)中,expr1是一個(gè)整數(shù)表達(dá)式。因此傳遞給 switch 和 case 語句的參數(shù)應(yīng)該是 int、 short、 char 或者 byte。long,string 都不能作用于swtich。 
    38 Hashtable和HashMap

      Hashtable繼承自Dictionary類,而HashMap是Java1.2引進(jìn)的Map interface的一個(gè)實(shí)現(xiàn) 
      HashMap允許將null作為一個(gè)entry的key或者value,而Hashtable不允許
    還有就是,HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因?yàn)閏ontains方法容易讓人引起誤解。
      最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在
    多個(gè)線程訪問Hashtable時(shí),不需要自己為它的方法實(shí)現(xiàn)同步,而HashMap就必須為之提供外同步。 
    Hashtable和HashMap采用的hash/rehash算法都大概一樣,所以性能不會(huì)有很大的差異。

    posted @ 2008-01-10 17:04 靈! 閱讀(239) | 評(píng)論 (0)編輯 收藏

    JAVA面試題匯總 三

    21 數(shù)組有沒有l(wèi)ength()這個(gè)方法? String有沒有l(wèi)ength()這個(gè)方法?

      數(shù)組沒有l(wèi)ength()這個(gè)方法,有l(wèi)ength的屬性。 
      String有有l(wèi)ength()這個(gè)方法。

    22 Overload和Override的區(qū)別。Overloaded的方法是否可以改變返回值的類型?

      方法的重寫Overriding和重載Overloading是Java多態(tài)性的不同表現(xiàn)。重寫Overriding是父類與子類之間多態(tài)性的一種表現(xiàn),重載Overloading是一個(gè)類中多態(tài)性的一種表現(xiàn)。如果在子類中定義某方法與其父類有相同的名稱和參數(shù),我們說該方法被重寫(Overriding)。子類的對(duì)象使用這個(gè)方法時(shí),將調(diào)用子類中的定義,對(duì)它而言,父類中的定義如同被“屏蔽”了。如果在一個(gè)類中定義了多個(gè)同名的方法,它們或有不同的參數(shù)個(gè)數(shù)或有不同的參數(shù)類型,則稱為方法的重載(Overloading)。 
    Overloaded的方法是可以改變返回值的類型。

    23 Set里的元素是不能重復(fù)的,那么用什么方法來區(qū)分重復(fù)與否呢? 是用==還是equals()? 它們有何區(qū)別?

      Set里的元素是不能重復(fù)的,那么用iterator()方法來區(qū)分重復(fù)與否。equals()是判讀兩個(gè)Set是否相等。 equals()和==方法決定引用值是否指向同一對(duì)象equals()在類中被覆蓋,為的是當(dāng)兩個(gè)分離的對(duì)象的內(nèi)容和類型相配的話,返回真值。 

    24最常見到的runtime exception。

    ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, CannotUndoException, ClassCastException, CMMException, ConcurrentModificationException, DOMException,EmptyStackException, IllegalArgumentException, IllegalMonitorStateException, IllegalPathStateException, IllegalStateException,ImagingOpException, IndexOutOfBoundsException, MissingResourceException, NegativeArraySizeException, NoSuchElementException, NullPointerException, ProfileDataException, ProviderException, RasterFORMatException, Secur 
    ityException, SystemException, UndeclaredThrowableException, UnmodifiableSetException, UnsupportedOperationException 

    25 error和exception有什么區(qū)別?

      error 表示恢復(fù)不是不可能但很困難的情況下的一種嚴(yán)重問題。比如說內(nèi)存溢出。不可能指望程序能處理這樣的情況。 
      exception 表示一種設(shè)計(jì)或?qū)崿F(xiàn)問題。也就是說,它表示如果程序運(yùn)行正常,從不會(huì)發(fā)生的情況。

    26 List, Set, Map是否繼承自Collection接口?

         List,Set是 
         Map不是
        
    27 abstract class和interface有什么區(qū)別?

      聲明方法的存在而不去實(shí)現(xiàn)它的類被叫做抽象類(abstract class),它用于要?jiǎng)?chuàng)建一個(gè)體現(xiàn)某些基本行為的類,并為該類聲明方法,但不能在該類中實(shí)現(xiàn)該類的情況。不能創(chuàng)建abstract 類的實(shí)例。然而可以創(chuàng)建一個(gè)變量,其類型是一個(gè)抽象類,并讓它指向具體子類的一個(gè)實(shí)例。不能有抽象構(gòu)造函數(shù)或抽象靜態(tài)方法。Abstract 類的子類為它們父類中的所有抽象方法提供實(shí)現(xiàn),否則它們也是抽象類為。取而代之,在子類中實(shí)現(xiàn)該方法。知道其行為的其它類可以在類中實(shí)現(xiàn)這些方法。 
      接口(interface)是抽象類的變體。在接口中,所有方法都是抽象的。多繼承性可通過實(shí)現(xiàn)這樣的接口而獲得。接口中的所有方法都是抽象的,沒有一個(gè)有程序體。接口只可以定義static final成員變量。接口的實(shí)現(xiàn)與子類相似,除了該實(shí)現(xiàn)類不能從接口定義中繼承行為。當(dāng)類實(shí)現(xiàn)特殊接口時(shí),它定義(即將程序體給予)所有這種接口的方法。然后,它可以在實(shí)現(xiàn)了該接口的類的任何對(duì)象上調(diào)用接口的方法。由于有抽象類,它允許使用接口名作為引用變量的類型。通常的動(dòng)態(tài)聯(lián)編將生效。引用可以轉(zhuǎn)換到接口類型或從接口類型轉(zhuǎn)換,instanceof 運(yùn)算符可以用來決定某對(duì)象的類是否實(shí)現(xiàn)了接口。 

    28 abstract的method是否可同時(shí)是static,是否可同時(shí)是native,是否可同時(shí)是synchronized?

      都不能

    29 接口是否可繼承接口? 抽象類是否可實(shí)現(xiàn)(implements)接口? 抽象類是否可繼承實(shí)體類(concrete class)?

      接口可以繼承接口。抽象類可以實(shí)現(xiàn)(implements)接口,抽象類可繼承實(shí)體類,但前提是實(shí)體類必須有明確的構(gòu)造函數(shù)。

    30 啟動(dòng)一個(gè)線程是用run()還是start()?

      啟動(dòng)一個(gè)線程是調(diào)用start()方法,使線程所代表的虛擬處理機(jī)處于可運(yùn)行狀態(tài),這意味著它可以由JVM調(diào)度并執(zhí)行。這并不意味著線程就會(huì)立即運(yùn)行。run()方法可以產(chǎn)生必須退出的標(biāo)志來停止一個(gè)線程。

    posted @ 2008-01-10 17:03 靈! 閱讀(195) | 評(píng)論 (0)編輯 收藏

    JAVA面試題匯總 二

    11   &和&&的區(qū)別。 
      &是位運(yùn)算符。&&是布爾邏輯運(yùn)算符。 

    12  HashMap和Hashtable的區(qū)別。

      都屬于Map接口的類,實(shí)現(xiàn)了將惟一鍵映射到特定的值上。 
      HashMap 類沒有分類或者排序。它允許一個(gè) null 鍵和多個(gè) null 值。 


      Hashtable 類似于 HashMap,但是不允許 null 鍵和 null 值。它也比 HashMap 慢,因?yàn)樗峭降摹?/p>

    13 Collection 和 Collections的區(qū)別。

        Collection是個(gè)java.util下的接口,它是各種集合結(jié)構(gòu)的父接口。
      Collections是個(gè)java.util下的類,它包含有各種有關(guān)集合操作的靜態(tài)方法。

    14 什么時(shí)候用assert。

      斷言是一個(gè)包含布爾表達(dá)式的語句,在執(zhí)行這個(gè)語句時(shí)假定該表達(dá)式為 true。 
    如果表達(dá)式計(jì)算為 false,那么系統(tǒng)會(huì)報(bào)告一個(gè) Assertionerror。它用于調(diào)試目的: 
    assert(a > 0); // throws an Assertionerror if a <= 0 
    斷言可以有兩種形式: 
    assert Expression1 ; 
    assert Expression1 : Expression2 ; 
      Expression1 應(yīng)該總是產(chǎn)生一個(gè)布爾值。 
      Expression2 可以是得出一個(gè)值的任意表達(dá)式。這個(gè)值用于生成顯示更多調(diào)試 
    信息的 String 消息。 
      斷言在默認(rèn)情況下是禁用的。要在編譯時(shí)啟用斷言,需要使用 source 1.4 標(biāo)記:
      javac -source 1.4 Test.java 
      要在運(yùn)行時(shí)啟用斷言,可使用 -enableassertions 或者 -ea 標(biāo)記。 
      要在運(yùn)行時(shí)選擇禁用斷言,可使用 -da 或者 -disableassertions 標(biāo)記。 
      要系統(tǒng)類中啟用斷言,可使用 -esa 或者 -dsa 標(biāo)記。還可以在包的基礎(chǔ)上啟用或者禁用斷言。 
      可以在預(yù)計(jì)正常情況下不會(huì)到達(dá)的任何位置上放置斷言。斷言可以用于驗(yàn)證傳遞給私有方法的參數(shù)。不過,斷言不應(yīng)該用于驗(yàn)證傳遞給公有方法的參數(shù),因?yàn)椴还苁欠駟⒂昧藬嘌裕蟹椒ǘ急仨殭z查其參數(shù)。不過,既可以在公有方法中,也可以在非公有方法中利用斷言測(cè)試后置條件。另外,斷言不應(yīng)該以任何方式改變程序的狀態(tài)。 

    15 GC是什么? 為什么要有GC? (基礎(chǔ))。

      GC是垃圾收集器。Java 程序員不用擔(dān)心內(nèi)存管理,因?yàn)槔占鲿?huì)自動(dòng)進(jìn)行管理。要請(qǐng)求垃圾收集,可以調(diào)用下面的方法之一:
      System.gc() 
      Runtime.getRuntime().gc()

    16 String s = new String("xyz");創(chuàng)建了幾個(gè)String Object?

      兩個(gè)對(duì)象,一個(gè)是“xyz”,一個(gè)是指向“xyz”的引用對(duì)象s。

    17 Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

      Math.round(11.5)返回(long)12,Math.round(-11.5)返回(long)-11;

    18 short s1 = 1; s1 = s1 + 1;有什么錯(cuò)? short s1 = 1; s1 += 1;有什么錯(cuò)?

      short s1 = 1; s1 = s1 + 1;有錯(cuò),s1是short型,s1+1是int型,不能顯式轉(zhuǎn)化為short型。可修改為s1 =(short)(s1 + 1) 。short s1 = 1; s1 += 1正確。

    19 sleep() 和 wait() 有什么區(qū)別? 搞線程的最愛

      sleep()方法是使線程停止一段時(shí)間的方法。在sleep 時(shí)間間隔期滿后,線程不一定立即恢復(fù)執(zhí)行。這是因?yàn)樵谀莻€(gè)時(shí)刻,其它線程可能正在運(yùn)行而且沒有被調(diào)度為放棄執(zhí)行,除非(a)“醒來”的線程具有更高的優(yōu)先級(jí) (b)正在運(yùn)行的線程因?yàn)槠渌蚨枞?nbsp;
      wait()是線程交互時(shí),如果線程對(duì)一個(gè)同步對(duì)象x 發(fā)出一個(gè)wait()調(diào)用,該線程會(huì)暫停執(zhí)行,被調(diào)對(duì)象進(jìn)入等待狀態(tài),直到被喚醒或等待時(shí)間到。 

    20 Java有沒有g(shù)oto? 
      Goto—java中的保留字,現(xiàn)在沒有在java中使用。

    posted @ 2008-01-10 17:02 靈! 閱讀(208) | 評(píng)論 (0)編輯 收藏

    JAVA面試題匯總 一

    1. Java中的異常處理機(jī)制的簡(jiǎn)單原理和應(yīng)用。 

    當(dāng)Java程序違反了Java的語義規(guī)則時(shí),Java虛擬機(jī)就會(huì)將發(fā)生的錯(cuò)誤表示為一個(gè)異常。違反語義規(guī)則包括2種情況。一種是Java類庫(kù)內(nèi)置的語義檢查。例如數(shù)組下標(biāo)越界,會(huì)引發(fā)IndexOutOfBoundsException;訪問null的對(duì)象時(shí)會(huì)引發(fā)NullPointerException。另一種情況就是Java允許程序員擴(kuò)展這種語義檢查,程序員可以創(chuàng)建自己的異常,并自由選擇在何時(shí)用throw關(guān)鍵字引發(fā)異常。所有的異常都是java.lang.Thowable的子類。 

    2. Java的接口和C++的虛類的相同和不同處。 

    由于Java不支持多繼承,而有可能某個(gè)類或?qū)ο笠褂梅謩e在幾個(gè)類或?qū)ο罄锩娴姆椒ɑ驅(qū)傩裕F(xiàn)有的單繼承機(jī)制就不能滿足要求。與繼承相比,接口有更高的靈活性,因?yàn)榻涌谥袥]有任何實(shí)現(xiàn)代碼。當(dāng)一個(gè)類實(shí)現(xiàn)了接口以后,該類要實(shí)現(xiàn)接口里面所有的方法和屬性,并且接口里面的屬性在默認(rèn)狀態(tài)下面都是public static,所有方法默認(rèn)情況下是public.一個(gè)類可以實(shí)現(xiàn)多個(gè)接口。 

    3. 垃圾回收的優(yōu)點(diǎn)和原理。并考慮2種回收機(jī)制。 

    Java語言中一個(gè)顯著的特點(diǎn)就是引入了垃圾回收機(jī)制,使c++程序員最頭疼的內(nèi)存管理的問題迎刃而解,它使得Java程序員在編寫程序的時(shí)候不再需要考慮內(nèi)存管理。由于有個(gè)垃圾回收機(jī)制,Java中的對(duì)象不再有“作用域”的概念,只有對(duì)象的引用才有“作用域”。垃圾回收可以有效的防止內(nèi)存泄露,有效的使用可以使用的內(nèi)存。垃圾回收器通常是作為一個(gè)單獨(dú)的低級(jí)別的線程運(yùn)行,不可預(yù)知的情況下對(duì)內(nèi)存堆中已經(jīng)死亡的或者長(zhǎng)時(shí)間沒有使用的對(duì)象進(jìn)行清除和回收,程序員不能實(shí)時(shí)的調(diào)用垃圾回收器對(duì)某個(gè)對(duì)象或所有對(duì)象進(jìn)行垃圾回收。回收機(jī)制有分代復(fù)制垃圾回收和標(biāo)記垃圾回收,增量垃圾回收。 

    4.線程同步的方法。 

    wait():使一個(gè)線程處于等待狀態(tài),并且釋放所持有的對(duì)象的lock。 

    sleep():使一個(gè)正在運(yùn)行的線程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法,調(diào)用此方法要捕捉InterruptedException異常。 

    notify():喚醒一個(gè)處于等待狀態(tài)的線程,注意的是在調(diào)用此方法的時(shí)候,并不能確切地喚醒某一個(gè)等待狀態(tài)的線程,而是由JVM確定喚醒哪個(gè)線程,而且不是按優(yōu)先級(jí)。 

    Allnotity():喚醒所有處入等待狀態(tài)的線程,注意并不是給所有喚醒線程一個(gè)對(duì)象的鎖,而是讓它們競(jìng)爭(zhēng)。 

    5. Error與Exception有什么區(qū)別? 

    Error表示系統(tǒng)級(jí)的錯(cuò)誤和程序不必處理的異常, 

    Exception表示需要捕捉或者需要程序進(jìn)行處理的異常。 

    6. 在java中一個(gè)類被聲明為final類型,表示了什么意思? 

       表示該類不能被繼承,是頂級(jí)類。
      
    7 heap和stack有什么區(qū)別。

       棧是一種線形集合,其添加和刪除元素的操作應(yīng)在同一段完成。棧按照后進(jìn)先出的方式進(jìn)行處理。堆是棧的一個(gè)組成元素。

    8談?wù)刦inal, finally, finalize的區(qū)別。

      final—修飾符(關(guān)鍵字)如果一個(gè)類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承。因此一個(gè)類不能既被聲明為 abstract的,又被聲明為final的。將變量或方法聲明為final,可以保證它們?cè)谑褂弥胁槐桓淖儭1宦暶鳛閒inal的變量必須在聲明時(shí)給定初值,而在以后的引用中只能讀取,不可修改。被聲明為final的方法也同樣只能使用,不能重載。 
      finally—異常處理時(shí)提供 finally 塊來執(zhí)行任何清除操作。如果拋出一個(gè)異常,那么相匹配的 catch 子句就會(huì)執(zhí)行,然后控制就會(huì)進(jìn)入 finally 塊(如果有的話)。 
      finalize—方法名。Java 技術(shù)允許使用 finalize() 方法在垃圾收集器將對(duì)象從內(nèi)存中清除出去之前做必要的清理工作。這個(gè)方法是由垃圾收集器在確定這個(gè)對(duì)象沒有被引用時(shí)對(duì)這個(gè)對(duì)象調(diào)用的。它是在 Object 類中定義的,因此所有的類都繼承了它。子類覆蓋 finalize() 方法以整理系統(tǒng)資源或者執(zhí)行其他清理工作。finalize() 方法是在垃圾收集器刪除對(duì)象之前對(duì)這個(gè)對(duì)象調(diào)用的。

    9  Anonymous Inner Class (匿名內(nèi)部類) 是否可以extends(繼承)其它類,是否可以implements(實(shí)現(xiàn))interface(接口)?

      匿名的內(nèi)部類是沒有名字的內(nèi)部類。不能extends(繼承) 其它類,但一個(gè)內(nèi)部類可以作為一個(gè)接口,由另一個(gè)內(nèi)部類實(shí)現(xiàn)。

    10  Static Nested Class 和 Inner Class的不同
    Nested Class (一般是C++的說法),Inner Class (一般是JAVA的說法)。Java內(nèi)部類與C++嵌套類最大的不同就在于是否有指向外部的引用上。
      注: 靜態(tài)內(nèi)部類(Inner Class)意味著1創(chuàng)建一個(gè)static內(nèi)部類的對(duì)象,不需要一個(gè)外部類對(duì)象,2不能從一個(gè)static內(nèi)部類的一個(gè)對(duì)象訪問一個(gè)外部類對(duì)象  .

    posted @ 2008-01-10 17:02 靈! 閱讀(227) | 評(píng)論 (0)編輯 收藏

    漢字編碼轉(zhuǎn)換

    漢字編碼轉(zhuǎn)換

    相關(guān):

    UNICODE 是為了處理包括中文,日文等字符而提出的一種通用的字符集。最初的UNICODE為雙字節(jié)字符集,即16位編碼,能夠包括65,536個(gè)字符。但這樣的容量并不能滿足所有需要,因此,現(xiàn)在的UNICODE已經(jīng)擴(kuò)展到4個(gè)字節(jié),能夠容納1,112,064 個(gè)字符,而這些在16位之后的擴(kuò)展背稱為增補(bǔ)字符。

    UTF-32 UTF-16 UTF-8 Unicode 標(biāo)準(zhǔn)的編碼字符集的字符編碼方案。

    UTF-8 使用一至四個(gè)字節(jié)的序列對(duì)編碼 Unicode 代碼點(diǎn)進(jìn)行編碼

    UTF-8 使用一至四個(gè)字節(jié)的序列對(duì)編碼 Unicode 代碼點(diǎn)進(jìn)行編碼。U+0000 至 U+007F 使用一個(gè)字節(jié)編碼,U+0080 至 U+07FF 使用兩個(gè)字節(jié),U+0800 至 U+FFFF 使用三個(gè)字節(jié),而 U+10000 至 U+10FFFF 使用四個(gè)字節(jié)。UTF-8 設(shè)計(jì)原理為:字節(jié)值 0x00 至 0x7F 始終表示代碼點(diǎn) U+0000 至 U+007F(Basic Latin 字符子集,它對(duì)應(yīng) ASCII 字符集)。這些字節(jié)值永遠(yuǎn)不會(huì)表示其他代碼點(diǎn),這一特性使 UTF-8 可以很方便地在軟件中將特殊的含義賦予某些 ASCII 字符。

      GB2312(1980 ) 一共收錄了 7445 個(gè)字符,包括 6763 個(gè)漢字和 682 個(gè)其它符號(hào)。漢字區(qū)的內(nèi)碼范圍高字節(jié)從 B0-F7 ,低字節(jié)從 A1-FE ,占用的碼位是 72*94=6768 。其中有 5 個(gè)空位是 D7FA-D7FE 。當(dāng)然也可以表示數(shù)字和字符(一個(gè)字節(jié),與 ASCII 表示相同)。

    要讀取一個(gè)以 GB2312 編碼的包含漢字、數(shù)字、字母的二進(jìn)制文件。

    String strName =Encoding.GetEncoding("gb2312").GetString(name,0,i) ;

    // name 是讀取的二進(jìn)制數(shù)組。

    這樣就能將二進(jìn)制數(shù)組轉(zhuǎn)換為 漢字、數(shù)字或字母

    同樣:也可以將包含漢字、數(shù)字、字母的字符串轉(zhuǎn)換為 二進(jìn)制數(shù)組保存到 二進(jìn)制文件。

    String unicodeString =   " 備用43E";

    Byte[] encodedBytes = Encoding.GetEncoding("gb2312").GetBytes(unicodeString);

    當(dāng)然也可以進(jìn)行二進(jìn)制數(shù)組與UNICODE,UTF-8等編碼方式的轉(zhuǎn)換

    Byte[] encodedBytes = utf8.GetBytes(unicodeString);

    String decodedString = utf8.GetString(encodedBytes);

    UnicodeEncoding unicode = new UnicodeEncoding();

    Byte[] encodedBytes = unicode.GetBytes(unicodeString);

    String decodedString = unicode.GetString(encodedBytes);

    posted @ 2008-01-10 11:46 靈! 閱讀(580) | 評(píng)論 (0)編輯 收藏

    JBuilderX快捷鍵

    F1 Help
    F3 查找下一個(gè)

    shift + F3 反向查找下一個(gè)

    ctrl + F 查找

    ctrl + p 路徑查找

    ctrl + F4 運(yùn)行到當(dāng)前位置
    ctrl+F6在jbuilder中,切換不同的文件
    Ctrl+F4關(guān)閉正在編輯的文件,
    Ctrl + F5切換工程


    F5 設(shè)置斷點(diǎn)

    F7 跟入

    F8 單步

    F9 運(yùn)行

    ctrl + F9 編譯工程

    shift + F9 調(diào)試模式運(yùn)行

    ctrl + shift + F9 編譯當(dāng)前類

    ctrl + H 顯示本類成員

    ctrl + J 顯示模板
    ctrl + shift + J 模板編輯

    ctrl + shift + c 自動(dòng)完成錯(cuò)誤捕捉代碼

    ctrl + Enter /mouseClick 當(dāng)前關(guān)鍵字追蹤

    ctrl + shit + 數(shù)字(0-9) 設(shè)置/去除標(biāo)簽

    ctrl + 數(shù)字(0-9) 返回標(biāo)簽位置

    ctrl + alt + -> / <- 返回最近訪問點(diǎn)

    ctrl + -> / <- 光標(biāo)跳過當(dāng)前單位詞

    ctrl + shift + -> / <- 選擇單位詞

    ctrl + 上下方向鍵 滾動(dòng)屏幕

    ctrl + home/end/pageup/pagedown

    shift +盤方向鍵/home/end/pageup/pagedown 選擇

    ctrl + e 增量式查找

    ctrl + w 捕捉離光標(biāo)最近的單詞

    ctrl + shift + h 參數(shù)查找

    ctrl + alt + space class insight

    ctrl + F4 關(guān)閉當(dāng)前類

    ctrl + shift + F4 關(guān)閉(顯示選擇)

    ctrl + B 切換窗體

    ctrl + F6 切換窗體

    ctrl + alt + p/c/m/z/s 視圖開關(guān)

    ctrl + o/n/c/v/x/p/a

    ctrl + g 到指定行

    Tab 格式化宿進(jìn)

    ctrl + / 注釋/去除注釋選擇行

    ctrl + shift + I 宿進(jìn)

    ctrl + shift + U 反向宿進(jìn)

    posted @ 2008-01-10 11:45 靈! 閱讀(202) | 評(píng)論 (0)編輯 收藏

    常用到的Eclipse快捷鍵

    常用到的Eclipse快捷鍵

    Ctrl+s                 存盤

    Ctrl+/                  注釋(取消)代碼

    Ctrl+shift+/       注釋代碼塊

    Ctrl+shift+\       取消代碼塊

    Alt+/                  代碼輔助/調(diào)出IF語句等程序模板:使用方法:打出if,按ALT+/

    Ctrl+D             刪除一行 

    Ctrl+Shift+D   debug 模式里顯示變量值

    Ctrl+1               快速修復(fù)  

    Ctrl+Shift+f     代碼格式化

    Ctrl+Shift+o    整理導(dǎo)入  

    Ctrl+f6             切換窗口  

    ctrl+shift+M   導(dǎo)入未引用的包

    ctrl+w             關(guān)閉單個(gè)窗口

    F3                      跳轉(zhuǎn)到類、變量的聲明

    F11                   運(yùn)行上次程序

    Ctrl + F11        調(diào)試上次程序

    Alt +                 回下一個(gè)編輯點(diǎn)

    ctrl+shift+T   查找工程中的類

    Alt-left arrow :    在導(dǎo)航歷史記錄(Navigation History)中后退。就像Web瀏覽器的后退按鈕一樣,在利用F3跳轉(zhuǎn)之后,特別有用。(用來返回原先編譯的地方)

    Alt+right arrow :   導(dǎo)航歷史記錄中向前。

    Control+Q :         回到最后依次編輯的地方。這個(gè)快捷鍵也是當(dāng)你在代碼中跳轉(zhuǎn)后用的。特別是當(dāng)你鉆的過深,忘記你最初在做什么的時(shí)候。

    ctrl+Alt+down     復(fù)制鼠標(biāo)所在行到下一行

    Alt+down arrow :    將一行或多行向下移動(dòng)。

    Alt+up arrow      將一行或多行 向上移動(dòng)。

    posted @ 2008-01-10 11:44 靈! 閱讀(276) | 評(píng)論 (0)編輯 收藏

    迭代器

    迭代這個(gè)名詞對(duì)于熟悉Java的人來說絕對(duì)不陌生。我們常常使用JDK提供的迭代接口進(jìn)行java collection的遍歷:

    Iterator it = list.iterator();
    while(it.hasNext()){
     //using “it.next();”do some businesss logic
    }

      而這就是關(guān)于迭代器模式應(yīng)用很好的例子。

      二、 定義與結(jié)構(gòu)

      迭代器(Iterator)模式,又叫做游標(biāo)(Cursor)模式。GOF給出的定義為:提供一種方法訪問一個(gè)容器(container)對(duì)象中各個(gè)元素,而又不需暴露該對(duì)象的內(nèi)部細(xì)節(jié)。

      從定義可見,迭代器模式是為容器而生。很明顯,對(duì)容器對(duì)象的訪問必然涉及到遍歷算法。你可以一股腦的將遍歷方法塞到容器對(duì)象中去;或者根本不去提供什么遍歷算法,讓使用容器的人自己去實(shí)現(xiàn)去吧。這兩種情況好像都能夠解決問題。

      然而在前一種情況,容器承受了過多的功能,它不僅要負(fù)責(zé)自己“容器”內(nèi)的元素維護(hù)(添加、刪除等等),而且還要提供遍歷自身的接口;而且由于遍歷狀態(tài)保存的問題,不能對(duì)同一個(gè)容器對(duì)象同時(shí)進(jìn)行多個(gè)遍歷。第二種方式倒是省事,卻又將容器的內(nèi)部細(xì)節(jié)暴露無遺。

      而迭代器模式的出現(xiàn),很好的解決了上面兩種情況的弊端。先來看下迭代器模式的真面目吧。

      迭代器模式由以下角色組成:

      1) 迭代器角色(Iterator):迭代器角色負(fù)責(zé)定義訪問和遍歷元素的接口。

      2) 具體迭代器角色(Concrete Iterator):具體迭代器角色要實(shí)現(xiàn)迭代器接口,并要記錄遍歷中的當(dāng)前位置。

      3) 容器角色(Container):容器角色負(fù)責(zé)提供創(chuàng)建具體迭代器角色的接口。

      4) 具體容器角色(Concrete Container):具體容器角色實(shí)現(xiàn)創(chuàng)建具體迭代器角色的接口——這個(gè)具體迭代器角色于該容器的結(jié)構(gòu)相關(guān)。

      迭代器模式的類圖如下:


      從結(jié)構(gòu)上可以看出,迭代器模式在客戶與容器之間加入了迭代器角色。迭代器角色的加入,就可以很好的避免容器內(nèi)部細(xì)節(jié)的暴露,而且也使得設(shè)計(jì)符號(hào)“單一職責(zé)原則”。

      注意,在迭代器模式中,具體迭代器角色和具體容器角色是耦合在一起的——遍歷算法是與容器的內(nèi)部細(xì)節(jié)緊密相關(guān)的。為了使客戶程序從與具體迭代器角色耦合的困境中脫離出來,避免具體迭代器角色的更換給客戶程序帶來的修改,迭代器模式抽象了具體迭代器角色,使得客戶程序更具一般性和重用性。這被稱為多態(tài)迭代。

      三、 舉例

      由于迭代器模式本身的規(guī)定比較松散,所以具體實(shí)現(xiàn)也就五花八門。我們?cè)诖藘H舉一例,根本不能將實(shí)現(xiàn)方式一一呈現(xiàn)。因此在舉例前,我們先來列舉下迭代器模式的實(shí)現(xiàn)方式。

      1.迭代器角色定義了遍歷的接口,但是沒有規(guī)定由誰來控制迭代。在Java collection的應(yīng)用中,是由客戶程序來控制遍歷的進(jìn)程,被稱為外部迭代器;還有一種實(shí)現(xiàn)方式便是由迭代器自身來控制迭代,被稱為內(nèi)部迭代器。外部迭代器要比內(nèi)部迭代器靈活、強(qiáng)大,而且內(nèi)部迭代器在java語言環(huán)境中,可用性很弱。

      2.在迭代器模式中沒有規(guī)定誰來實(shí)現(xiàn)遍歷算法。好像理所當(dāng)然的要在迭代器角色中實(shí)現(xiàn)。因?yàn)榧缺阌谝粋€(gè)容器上使用不同的遍歷算法,也便于將一種遍歷算法應(yīng)用于不同的容器。但是這樣就破壞掉了容器的封裝——容器角色就要公開自己的私有屬性,在java中便意味著向其他類公開了自己的私有屬性。

      那我們把它放到容器角色里來實(shí)現(xiàn)好了。這樣迭代器角色就被架空為僅僅存放一個(gè)遍歷當(dāng)前位置的功能。但是遍歷算法便和特定的容器緊緊綁在一起了。

      而在Java Collection的應(yīng)用中,提供的具體迭代器角色是定義在容器角色中的內(nèi)部類。這樣便保護(hù)了容器的封裝。但是同時(shí)容器也提供了遍歷算法接口,你可以擴(kuò)展自己的迭代器。

      好了,我們來看下Java Collection中的迭代器是怎么實(shí)現(xiàn)的吧。

    //迭代器角色,僅僅定義了遍歷接口

    public interface Iterator {
     boolean hasNext();
     Object next();
     void remove();
    }

    //容器角色,這里以List為例。它也僅僅是一個(gè)接口,就不羅列出來了
    //具體容器角色,便是實(shí)現(xiàn)了List接口的ArrayList等類。為了突出重點(diǎn)這里指羅列和迭代器相關(guān)的內(nèi)容
    //具體迭代器角色,它是以內(nèi)部類的形式出來的。AbstractList是為了將各個(gè)具體容器角色的公共部分提取出來而存在的。

    public abstract class AbstractList extends AbstractCollection implements List {
    ……
    //這個(gè)便是負(fù)責(zé)創(chuàng)建具體迭代器角色的工廠方法
    public Iterator iterator() {
     return new Itr();
    }

    //作為內(nèi)部類的具體迭代器角色

    private class Itr implements Iterator {
     int cursor = 0;
     int lastRet = -1;
     int expectedModCount = modCount;

     public boolean hasNext() {
      return cursor != size();
     }

     public Object next() {
      checkForComodification();
      try {
       Object next = get(cursor);
       lastRet = cursor++;
       return next;
      } catch(IndexOutOfBoundsException e) {
       checkForComodification();
       throw new NoSuchElementException();
      }
     }

     public void remove() {
      if (lastRet == -1)
       throw new IllegalStateException();
       checkForComodification();

      try {
       AbstractList.this.remove(lastRet);
       if (lastRet < cursor)
        cursor--;
       lastRet = -1;
       expectedModCount = modCount;
      } catch(IndexOutOfBoundsException e) {
       throw new ConcurrentModificationException();
      }
     }

     final void checkForComodification() {
      if (modCount != expectedModCount)
       throw new ConcurrentModificationException();
     }
    }

      至于迭代器模式的使用。正如引言中所列那樣,客戶程序要先得到具體容器角色,然后再通過具體容器角色得到具體迭代器角色。這樣便可以使用具體迭代器角色來遍歷容器了……

      四、 實(shí)現(xiàn)自己的迭代器

      在實(shí)現(xiàn)自己的迭代器的時(shí)候,一般要操作的容器有支持的接口才可以。而且我們還要注意以下問題:

      在迭代器遍歷的過程中,通過該迭代器進(jìn)行容器元素的增減操作是否安全呢?

      在容器中存在復(fù)合對(duì)象的情況,迭代器怎樣才能支持深層遍歷和多種遍歷呢?

      以上兩個(gè)問題對(duì)于不同結(jié)構(gòu)的容器角色,各不相同,值得考慮。

      五、 適用情況

      由上面的講述,我們可以看出迭代器模式給容器的應(yīng)用帶來以下好處:

      1) 支持以不同的方式遍歷一個(gè)容器角色。根據(jù)實(shí)現(xiàn)方式的不同,效果上會(huì)有差別。

      2) 簡(jiǎn)化了容器的接口。但是在java Collection中為了提高可擴(kuò)展性,容器還是提供了遍歷的接口。

      3) 對(duì)同一個(gè)容器對(duì)象,可以同時(shí)進(jìn)行多個(gè)遍歷。因?yàn)楸闅v狀態(tài)是保存在每一個(gè)迭代器對(duì)象中的。

      由此也能得出迭代器模式的適用范圍:

      1) 訪問一個(gè)容器對(duì)象的內(nèi)容而無需暴露它的內(nèi)部表示。

      2) 支持對(duì)容器對(duì)象的多種遍歷。

      3) 為遍歷不同的容器結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口(多態(tài)迭代)。

      六、 總結(jié)

      迭代器模式在我們的應(yīng)用中很廣泛,希望本文能幫助你理解它。如有不對(duì)之處,還請(qǐng)不吝指正。

    posted @ 2008-01-10 11:42 靈! 閱讀(221) | 評(píng)論 (0)編輯 收藏

    Hibernate 3新增XML關(guān)系持久性介紹(轉(zhuǎn))

    非常感謝最近發(fā)布的Hibernate 3中的XML持久性特性,Java開發(fā)者現(xiàn)在擁有了一個(gè)框架組件,它為易于實(shí)現(xiàn)的對(duì)象關(guān)系(OR)和XML持久性提供了高效的和一致的方法。

      Hibernate的易用性、高性能和對(duì)象關(guān)系持久性等高級(jí)特性給IT界帶來了很大的驚喜。 Hibernate的最新版本(版本3,3月29日發(fā)布的)給產(chǎn)品API帶來了一個(gè)重要的新特性:XML持久性。有了Hibernate 3之后,Java應(yīng)用程序開發(fā)者可以輕易地把XML文檔合并到關(guān)系型數(shù)據(jù)庫(kù)中。

      這個(gè)新特性應(yīng)該明確地告訴已有的Hibernate開發(fā)者,因?yàn)樗沧裱璓OJO(純的舊Java對(duì)象)相同的一致性方法,需要學(xué)習(xí)的知識(shí)最少。XML持久性的優(yōu)點(diǎn)也應(yīng)該介紹給新用戶。本文講解的是Hibernate 3持久性方法。

      XML持久性為什么重要

      大多數(shù)大型商業(yè)數(shù)據(jù)庫(kù)都支持某種形式的本地XML持久性。由于XML持久性是一個(gè)相對(duì)較新的機(jī)制--即使對(duì)大型廠商也是如此,這個(gè)領(lǐng)域中的標(biāo)準(zhǔn)還在不斷地浮現(xiàn)。其結(jié)果是,為了把無處不在的關(guān)系型持久性機(jī)制與日益增長(zhǎng)的XML解決方案集成在一起,架構(gòu)師必須依賴廠商特定的特性或者實(shí)現(xiàn)定制的XML持久性框架組件。這兩個(gè)選擇都沒有太大的吸引力。廠商特定的特性不是普及的,因?yàn)榭赡墚a(chǎn)生廠商封鎖(lock-in),而定制的框架組件實(shí)現(xiàn)可能耗費(fèi)大量的時(shí)間和財(cái)力,導(dǎo)致代碼難于維護(hù)。

      在OR(對(duì)象關(guān)系)持久性方面,Hibernate XML持久性是一個(gè)自然而然的解決方案。它可以跨越Hibernate支持的所有關(guān)系型平臺(tái)(如虛擬的或真實(shí)的關(guān)系型平臺(tái))移動(dòng),允許自由的遷移對(duì)象、基于XML的應(yīng)用程序和集成解決方案而不用擔(dān)心下層的關(guān)系型實(shí)現(xiàn)方法。

      體系結(jié)構(gòu)的細(xì)節(jié)信息

      Hibernate是一個(gè)良好架構(gòu)的框架組件,它無縫地利用了本地的環(huán)境,不需要用戶進(jìn)行任何特殊的干涉或安裝操作。從一個(gè)數(shù)據(jù)庫(kù)切換到另外一個(gè)數(shù)據(jù)庫(kù)通常只需要改變驅(qū)動(dòng)程序,并配置Hibernate(在線配置設(shè)置信息)來使用另外一種數(shù)據(jù)庫(kù)語言。

      Hibernate利用dom4j框架組件進(jìn)行XML的分析和維護(hù)。如果需要完全利用Hibernate的XML特性,你就必須對(duì)dom4j非常熟悉。一般來說,你會(huì)發(fā)現(xiàn)dom4j比Java提供的JAXP或與JAXP兼容的XML分析器要容易使用一些。它要求我們學(xué)習(xí)的相關(guān)知識(shí)較少,并且利用最少的dom4j知識(shí)你就能夠高效率地使用Hibernate XML持久性。

    實(shí)際例子:價(jià)格目錄同步

      通用的電子商務(wù)案例可以演示XML關(guān)系持久性機(jī)制的作用。我們來考慮一個(gè)示例,在這個(gè)例子中XML集成了在線零售商和供應(yīng)商之間的產(chǎn)品標(biāo)價(jià)目錄。

      該電子目錄包含了已標(biāo)價(jià)的產(chǎn)品列表。在線商店銷售產(chǎn)品,通過自己的存貨清單來管理(類似于Amazon與Toys-R-Us和運(yùn)動(dòng)產(chǎn)品商店之間的關(guān)系)。為了精確地和有效地反映價(jià)格的變化,在線零售商必須頻繁地接收產(chǎn)品價(jià)格信息。它把這些信息存放為XML文檔,如下所示:

    <products>
    <product prod_id="3" sku="100101">
    <description>Athlete mode body fat scale</description>
    <list_price>100.00</list_price>
    <drop_price>60.00</drop_price>
    </product>
    <product prod_id="4" sku="100102">
    <description>Thermometer</description>
    <list_price>20.00</list_price>
    <drop_price>11.00</drop_price>
    </product>
    </products>

      全面的主要的產(chǎn)品價(jià)格列表存儲(chǔ)在數(shù)據(jù)庫(kù)中,如下所示:

    CREATE TABLE PRODUCT
    (
    id INT UNIQUE NOT NULL,
    description VARCHAR(45) NOT NULL,
    sku VARCHAR(45) UNIQUE NOT NULL,
    list_price FLOAT,
    base_price FLOAT,
    order_price FLOAT,
    CONSTRAINT PK_PRODUCT PRIMARY KEY (id )
    )

      在線零售商通過已有的OR映射提供定價(jià)目錄的Web表現(xiàn)形式,定價(jià)產(chǎn)品都表現(xiàn)為demo.Product Java對(duì)象:

    /** Product對(duì)象表現(xiàn)了定價(jià)目錄項(xiàng)*/
    public class Product {
    int id;
    String sku;
    String description;
    Double listPrice;
    Double basePrice;
    Double orderPrice;

      這些對(duì)象按照下面的方式映射(為了清楚,我們列出了列名,盡管在屬性和列名相匹配的時(shí)候Hibernate可以自動(dòng)地把屬性映射為列名):

    <?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 package="demo">
    <class name="Product"
    table="product"
    node="product">
    <id name="id"
    type="int"
    node="@prod_id"
    column="id">
    </id>
    <property name="sku" node="@sku" column="sku" not-null="true"/>
    <property name="description" node="description" column="description" not-null="true"/>
    <property name="listPrice" node="list_price" column="list_price" />
    <property name="basePrice" node="drop_price" column="base_price"/>
    <property name="orderPrice" column="order_price"/>
    </class>
    </hibernate-mapping>

      在這種情況下,Hibernate的XML關(guān)系持久性就非常方便了。由于該電子商務(wù)應(yīng)用程序接收了包含產(chǎn)品價(jià)格更新的XML,它就利用Hibernate的XML持久性機(jī)制把這些XML寫入到產(chǎn)品數(shù)據(jù)庫(kù)中。Hibernate提供了幾種XML持久性選擇,包括Hibernate的saveOrUpdate方法:

    document = saxReader.read(inputXML);
    List users = document.selectNodes("http://product");
    try {
     Session session = ibernateUtil.sessionFactory.openSession();
     Transaction transaction = session.beginTransaction();
     Session dom4jSession = session.openSession(EntityMode.DOM4J);
     Iterator iter = users.iterator();
     while (iter.hasNext()) {
      Object next = iter.next();
      dom4jSession.saveOrUpdate("demo.Product", next );
     }// end while
    transaction.commit();
    session.close(); 

      XML映射語法

      上面的例子中使用的映射文件不用于Hibernate 2的映射文件。Hibernate 3引入了幾種專門用于XML持久性的新映射類型。

      主要的新映射屬性是節(jié)點(diǎn)(node),它與被映射的XML文檔中的一個(gè)元素或文檔中的屬性相關(guān)聯(lián)。

      一個(gè)"節(jié)點(diǎn)"可能表現(xiàn)為下面的某種映射:

      · "element-name(元素名)":在例子中,<product></product>元素會(huì)被表示為node="product"。

      · "@attribute-name(屬性名)":在例子中,node="@sku"會(huì)被映射為XML屬性<product sku="1001001">。

      · ".(句點(diǎn))":映射為元素的父元素(例如<products>就<product>是的父元素)。

      · "element-name/@attribute-name(元素名/屬性名)":映射為命名元素的屬性(product/@sku)。

      XML持久性并非Hibernate的主要任務(wù)

      Hibernate 3框架組件高效率地實(shí)現(xiàn)了目前最通用的一些方法(除了LDAP之外)。Java社團(tuán)現(xiàn)在擁有了一套框架組件,它為易于實(shí)現(xiàn)的OR和XML持久性提供了高效率的和一致性的方法。

      在我們知道上面一些內(nèi)容之后,了解Hibernate項(xiàng)目的任務(wù)是很重要的。盡管Hibernate 3的XML特性非常有用、有吸引力,但是它們并不是用來代替最流行的XML編組(marshalling)和轉(zhuǎn)換(transformation)框架組件的。不管它的OR映射解決方案多么完善,我們都不應(yīng)該期待Hibernate成為主流的XML維護(hù)框架組件(根據(jù)Hibernate的作者Gavin King在TheServerSide Java Symposium 2005上的發(fā)言)。

      由于這個(gè)原因,你應(yīng)該把XML持久性特性看作是已有的強(qiáng)大的Hibernate框架組件的有用的擴(kuò)展,它允許你輕易地把現(xiàn)在流行的其它的數(shù)據(jù)表現(xiàn)機(jī)制合并到自己的應(yīng)用程序中。但是,如果你必須處理復(fù)雜的集成和轉(zhuǎn)換情況,最好去尋找其它的XML專用的框架組件。

    posted @ 2008-01-10 11:41 靈! 閱讀(280) | 評(píng)論 (0)編輯 收藏

    hibernate入門

    一、首先學(xué)習(xí)hibernate.cfg.xml配置文件的具體配置
    <?xml version="1.0" encoding="UTF-8"?>

    <!--指定該文件的官方dtd-->
    <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd" >
    <hibernate-configuration>
      <session-factory>
        <!-- 顯示sql語言 -->
        <property name="show_sql">true</property>
        <!-- sql語言 -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- jdbc驅(qū)動(dòng)程式 -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- jdbc url -->
        <property name="connection.url">jdbc:mysql://localhost:3306/test</property>
        <!-- 數(shù)據(jù)庫(kù)用戶名 -->
        <property name="connection.username">root</property>
        <!-- 數(shù)據(jù)庫(kù)密碼 -->
        <property name="connection.password">wyq</property>
        <!-- C3P0連接池設(shè)定 -->
        <!--最小連接數(shù)-->
        <property name="c3p0.min_size">5</property>
        <!--最大連接數(shù)-->
        <property name="c3p0.max_size">20</property>
       <!--延遲所允許的時(shí)間-->
        <property name="c3p0.timeout">1800</property>
       <!--緩存所允許的最大連接數(shù)-->
        <property name="c3p0.max_statements">50</property>
        <!-- 每隔100筆資料送入資料庫(kù),清除緩存(定期清除緩存,減小壓力) -->
        <property name="hibernate.jdbc.batch_size">100</property>
        <!-- 設(shè)定事務(wù)管理的工廠類 -->
        <property name="hibernate.transaction.factiory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
       <mapping resource="com/wyq/hibernate/pojo/User.hbm.xml"/>
       <mapping resource="com/wyq/hibernate/pojo/TUser.hbm.xml"/>
       <mapping resource="com/wyq/hibernate/pojo/Room.hbm.xml"/>
      </session-factory>
    </hibernate-configuration>
    需要的jar包有c3p0.jar,hibernate3.jar,數(shù)據(jù)庫(kù).jar,log4j.jar


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

    1、讀取配置文件獲得連接
       讀取hibernate.cfg.xml配置文件,hibernate.cfg.xml文件放在Classpath下,使用下面的方式讀入該文件
          //Configuration 負(fù)責(zé)管理hibernate配置信息
          Configuration config=new Configuration().configure();
          //根據(jù)config建立SessionFactory
          //SessionFactory用于建立Session
          SessionFactory sessionFactory=config.buildSessionFactory();
          //開啟session,相當(dāng)于jdbc的Connection
          session = sessionFactory.openSession();

    2、Criteria 基本資料查詢
    (1)標(biāo)準(zhǔn)查詢:
          //創(chuàng)建查詢標(biāo)準(zhǔn)
          Criteria criteria=session.creteCriteria(User.class);
          //查詢條件
          criteria.add(Expression.eq("name","caterpillar"));
    ************************************************************************************
    Expression.eq(String s1,String s2)---------->相等s1=s2
    Expression.allEq(Map map)    --------------->多個(gè)屬性-值對(duì)應(yīng)關(guān)系,多個(gè)Expression.eq疊加
    Expression.gt(String s1,String s2)----------->大于s1>s2
    Expression.ge(String s1,String s2)----------->大于等于s1>=s2
    Expression.lt(String s1,String s2)------------>小于s1<s2
    Expression.le(String s1,String s2)------------>小于等于s1<=s2
    Expression.between(String s1,int s2,int s3)--->s2<s1<s3
    Expression.like(String s1,String s2)------------>s1 like s2
    比較2個(gè)屬性
    Expression.eqProperty(String s1,String s2)--->s1=s2
    Expression.gtProperty(String s1,String s2)---->s1>s2
    Expression.geProperty(String s1,String s2)---->s1>=s2
    Expression.ltProperty(String s1,String s2)----->s1<s2
    Expression.leProperty(String s1,String s2)----->s1<=s2
    Expression.and()----->Expression.and(Expression.eq("String s1,String s2"),Expression.eq(String s3,String s4))
    Expression.or()
    ************************************************************************************
    (2)高級(jí)查詢
    一、可以使用Criteria進(jìn)行查詢,并用order對(duì)結(jié)果進(jìn)行排序。
    //設(shè)置從第幾條開始取的記錄
    criteria.setFirstResult(100);
    //最多取的幾條記錄
    criteria.setMaxResults(20);
    //對(duì)結(jié)果進(jìn)行排序
    criteria.addOrder(Order.asc(String s1));
    criteria.addOrder(Order.desc(String s2));

    二、可以對(duì)查詢結(jié)果進(jìn)行統(tǒng)計(jì)操作,使用Projections的rowCount(),count(),max(),min(),countDistinct()等方法:
    例如:criteria.setProjection(Projections.max("age"));

    三、還可以用Projections的groupProperty()來對(duì)結(jié)果進(jìn)行分組
    例如:criteria.setProjection(Projections.groupProperty("age"));

    (***)四、結(jié)合統(tǒng)計(jì)與分組的功能,可以用ProjectionList
    例如:ProjectionList projectionList =Projections.projectionList();
                projectionList.add(Projections.groupProperty("age"));
                projectionList.add(Projections.rowCount());
                criteria.setProjection(projectionList);
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
          //查詢所有記錄
          List users=criteria.list();
          Iterator iterator=users.iterator();
          while(iterator.hasNext()){
             User user=(User)iterator.next();
             System.out.println(user.getId()+"\t"+user.getName()+"/"+user.getAge());
    }
    3、criteria的增、刪、改(還不完善)
    在用到增、刪、改時(shí),必須先聲明事務(wù)
    增加:
      Transaction tx = session.beginTransaction();//Transaction表示一組會(huì)話操作
      session.save(user);//將事物映射到數(shù)據(jù)庫(kù)進(jìn)行存儲(chǔ)
      tx.commit();
      session.close();
    刪除:
      Session session=this.getSession();
      User user=(User)session.get(User.class, new Integer(1));
      Transaction tx = session.beginTransaction();//Transaction表示一組會(huì)話操作
      session.delete(user);//將事物映射到數(shù)據(jù)庫(kù)進(jìn)行存儲(chǔ)
      tx.commit();
      session.close();

    修改:
      Session session=this.getSession();
      User user =(User)session.get(User.class,new Integer(2));//創(chuàng)建持久化的事物
      user.setName("wyqqqqqqqqqq");
      user.setAge(new Integer(30));
      Transaction tx = session.beginTransaction();//Transaction表示一組會(huì)話操作
      session.update(user);//將事物映射到數(shù)據(jù)庫(kù)進(jìn)行存儲(chǔ)
      tx.commit();
      session.close();
    ----------------------------------------------------------------------------------------------------------------------
    一、Query查詢可以先設(shè)定查詢參數(shù),之后通過set等方法,將指定的參數(shù)值添入.還可以使用命名參數(shù)
    Session session = sessionFactory.openSession();
    Query query = session.createQuery("select user.name from User as user where user.age>?(
    :minAge )");
    query.setInteger(0,25);
    query.setInteger("minAge",25);
    List names=query.list();
    Iterator iterator = names.iterator();
    while(iterator.hasNext()){
          System.out.println(iterator.next());
    }
    session.close();

    二、如果查詢整個(gè)表直接使用from User如果針對(duì)某個(gè)屬性使用select user.name from User as user
    使用hql可以更接近我們平時(shí)的jdbc編程,和把sql語句寫在程序中差不多,另外,也可以將sql語句寫在配置文件中。



    --------------------------------------------------------------------------------------------------------------------------
       多表關(guān)聯(lián)
    一、多對(duì)一進(jìn)行關(guān)聯(lián)(多個(gè)學(xué)生對(duì)應(yīng)同一間宿舍)---學(xué)生是主體,宿舍是附體,關(guān)聯(lián)關(guān)系<many-to-one>在主體學(xué)生中設(shè)置,在學(xué)生類中設(shè)置宿舍類,由于宿舍類只有一個(gè)可以直接用類來設(shè)置,在映射學(xué)生類(User)中包含宿舍這個(gè)類(Room),在映射配置文件(User.hbm.xml)中定義

    <many-to-one name="room" column="room_id" cascade="save-update" class="com.wyq.hibernate2.Room"></many-to-one>

    哪個(gè)是主體類就在哪個(gè)配置文件定義關(guān)聯(lián)關(guān)系.

    cascade屬性:表示關(guān)聯(lián)對(duì)象的持久化,該屬性也要設(shè)置在主體中,作用就是當(dāng)主控方執(zhí)行操作時(shí),關(guān)聯(lián)對(duì)象(被動(dòng)方)是否同步執(zhí)行同一操作.
    cascade的值:all:表示所有情況下都進(jìn)行級(jí)聯(lián)操作.
                            none:所有情況下都不進(jìn)行級(jí)聯(lián)操作
                            save-update:在執(zhí)行save-update時(shí)進(jìn)行級(jí)聯(lián)操作.
                            delete:在執(zhí)行delete時(shí)進(jìn)行級(jí)聯(lián)操作.

    注意:使用cascade自動(dòng)持久化時(shí),會(huì)先檢查被關(guān)聯(lián)物件的id屬性,未被持久化的物件之id屬性是由unsaved-value決定,預(yù)設(shè)是null,如果您使用long這樣的原生型態(tài)(primitive type)時(shí),則必須自行指定預(yù)設(shè)值.

    例如:<id name="id" column="ROOM_ID" unsaved-value="0">
                <generator class="increment"/>
            </id>

    如果您不想額外設(shè)定unsaved-value資訊,則可以將long改為L(zhǎng)ong,這可以符合預(yù)設(shè)的unsaved-value為null的設(shè)定 .

    二、一對(duì)多進(jìn)行關(guān)聯(lián)(一間宿舍對(duì)應(yīng)多個(gè)學(xué)生)---宿舍是主體,學(xué)生是附體,關(guān)聯(lián)關(guān)系<one-to-many>在主體宿舍中設(shè)置,由于要在宿舍類中設(shè)置學(xué)生類,一個(gè)宿舍包含多個(gè)學(xué)生,所以在宿舍類中要用Set類來進(jìn)行設(shè)置,用set類(private Set users = new HashSet();)來存儲(chǔ)多個(gè)學(xué)生類,在映射宿舍類(Room)中要包含<set>這個(gè)節(jié)點(diǎn),用來與user相關(guān)聯(lián)

    例如:<set name="users" table="USER">
                <key column="ROOM_ID"/>
                <one-to-many class="onlyfun.caterpillar.User"/>
            </set>

    name:表示屬性,table:表示關(guān)聯(lián)的表名,key:表示通過什么字段進(jìn)行關(guān)聯(lián),<one-to-many>:表示關(guān)聯(lián)類。這里也可以使用cascade屬性。

    三、在表關(guān)聯(lián)的設(shè)計(jì)中,不論是一對(duì)多還是多對(duì)一,都要將關(guān)聯(lián)字段設(shè)置在多的那一方。
    例如:user表格和room表格,要將關(guān)聯(lián)字段room_id設(shè)置在user表格中。

    四、一對(duì)一進(jìn)行關(guān)聯(lián)(一個(gè)人只有一個(gè)房間,一個(gè)房間也只有一個(gè)人)。
    可以通過2中方式進(jìn)行關(guān)聯(lián):

    (1)、通過外鍵進(jìn)行關(guān)聯(lián):在多對(duì)一的例子中就是通過外鍵進(jìn)行關(guān)聯(lián)的.
    在user-room的設(shè)置中(user.hbm.xml):
    <many-to-one name="room"
                         column="ROOM_ID"
                         class="onlyfun.caterpillar.Room"
                         cascade="all"
                         unique="true"/>

    其中unique表示限制一個(gè)User有一獨(dú)有的 Room,這只是單向的,說明一個(gè)user只有一個(gè)room.
    在room-user的設(shè)置中(room.hbm.xml):
    <one-to-one name="user"
                        class="onlyfun.caterpillar.User"
                        property-ref="room"/>
    這樣就完成了雙向的一對(duì)一關(guān)聯(lián),property-ref告訴hibernate,查詢出user并將其參考至room。
    (2)、通過主鍵進(jìn)行關(guān)聯(lián):限制兩個(gè)資料表的主鍵使用相同的值,如此一個(gè)User與Room就是一對(duì)一關(guān)係
    user.hbm.xml:
    <one-to-one name="room"
                        class="onlyfun.caterpillar.Room"
                        cascade="all"/>
    room.hbm.xml:
    <one-to-one name="user"
                        class="onlyfun.caterpillar.User"
                        constrained="true"/>

    使用constrained="true"告訴Hibernate參考至User的主鍵

    五、雙向關(guān)聯(lián),就是將一和二結(jié)合起來,如果將關(guān)聯(lián)的維護(hù)交給User的話會(huì)比較容易,因?yàn)槊總€(gè)User都對(duì)應(yīng)至一個(gè)Room,在儲(chǔ)存時(shí)並用像Room一樣必須對(duì)Set中的每個(gè)物件作檢查,為了將關(guān)聯(lián)的維護(hù)交給User,我們可以在Room.hbm.xml中的<set>修改,加上inverse="true",表示將關(guān)聯(lián)的維護(hù)「反過來」交給User作

     例如:<set name="users" table="users" iinverse="true" cascade="all">
                  <key  column="room_id"/>
                  <one-to-many class="onlyfun.caterpillar.User"/>

    在設(shè)立雙向關(guān)聯(lián)時(shí),關(guān)聯(lián)由多對(duì)一中「多」的哪一方維護(hù),會(huì)比由「一」的哪一方維護(hù)來的方便,在Hibernate可以藉由inverse來設(shè)定,不設(shè)定inverse基本上也可以運(yùn)行,但是效能會(huì)較差。


    ------------------------------------------------------------------------------------------------------------------------
          在Hibernate中,集合類的映射可以延遲初始(Lazy Initialization),在多對(duì)一或者一對(duì)多中,都可以使用延遲初始,例如:一個(gè)用戶(user對(duì)應(yīng)user表)有多個(gè)email地址(address對(duì)應(yīng)address表),也就是在真正索取該物件的資料時(shí),才向資料庫(kù)查詢,就上次例子來說,就是我們?cè)谧x取User時(shí),先不取得其中的 addrs屬性中之物件資料,由於只需要讀取User的name屬性,此時(shí)我們只要執(zhí)行一次select即可,真正需要addrs的資料時(shí),才向資料庫(kù)要求。在含有集合類的user.hbm.xml中要如下設(shè)置:

      <set name="addrs" table="ADDRS" lazy="true">
                <key column="USER_ID"/>
                <element type="string" column="ADDRESS" not-null="true"/>
            </set>

    --------------------------------------------------------------------------------------------------------------------------
          session是hibernate運(yùn)做的核心,是有SessionFactory所創(chuàng)建,sessionFactory是線程安全的,你可以讓多個(gè)線程同時(shí)存取SessionFactory,而不會(huì)有資源共用的問題,然而session不是設(shè)計(jì)為線程安全的,所以讓多個(gè)線程共用一個(gè)session,將發(fā)生資料共用而發(fā)生混亂的問題.下面是一個(gè)標(biāo)準(zhǔn)類.

    import java.io.Serializable;
    import net.sf.hibernate.HibernateException;
    import net.sf.hibernate.Session;
    import net.sf.hibernate.SessionFactory;
    import net.sf.hibernate.Transaction;
    public class HibernateSessionUtil implements Serializable
    {
         //創(chuàng)建線程局部變量 tLocalsess 
        public static final ThreadLocal tLocalsess = new ThreadLocal();
       //創(chuàng)建線程局部變量 tLocaltx
    public static final ThreadLocal tLocaltx = new ThreadLocal();
          //取得session
        public static Session currentSession(){
             //從線程變量tLocalsess中,取得當(dāng)前session
    Session session = (Session) tLocalsess.get();
    //判斷session是否為空,如果為空,將創(chuàng)建一個(gè)session,并付給線程變量tLocalsess
        try{
    if (session == null){
    session = openSession();
    tLocalsess.set(session);
    }
    }catch (HibernateException e){
    throw new InfrastructureException(e);
    }
    return session;
    }
    //關(guān)閉當(dāng)前session
        public static void closeSession(){
    
             //從線程變量tLocalsess中,取得當(dāng)前session
    Session session = (Session) tLocalsess.get();
             //設(shè)置線程變量tLocalsess為空
    tLocalsess.set(null);
    try{
                //關(guān)閉session
    if (session != null && session.isOpen()){
    session.close();
    }
    }catch (HibernateException e){
    throw new InfrastructureException(e);
    }
    }
    //事物處理
        public static void beginTransaction(){
          //從線程變量tLocaltx中取得事物管理對(duì)象Transaction
            Transaction tx = (Transaction) tLocaltx.get();
    try{
                //如果為空就從session中創(chuàng)建一個(gè)tx
    if (tx == null){
    tx = currentSession().beginTransaction();
    tLocaltx.set(tx);
    }
    }catch (HibernateException e){
    throw new InfrastructureException(e);
    }
    }
    //提交事物
        public static void commitTransaction(){
          //取得事物
    Transaction tx = (Transaction) tLocaltx.get();
    try{
                //如果不為空就提交
    if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack())
    tx.commit();
    tLocaltx.set(null);
    }catch (HibernateException e){
    throw new InfrastructureException(e);
    }
    }
        //事物回滾    
        public static void rollbackTransaction(){
             //取得tx事物
    Transaction tx = (Transaction) tLocaltx.get();
    try{
                //將變量清空
    tLocaltx.set(null);
    if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()){
                    //事物回滾
    tx.rollback();
    }
    }catch (HibernateException e){
    throw new InfrastructureException(e);
    }
    }
    
       //取得session
    private static Session openSession() throws HibernateException{
    return getSessionFactory().openSession();
    }
    
       //取得sessionFactory
    private static SessionFactory getSessionFactory() throws HibernateException{
    return SingletonSessionFactory.getInstance();
    }
    }
    filter的代碼:
    public class HibernateSessionCloser implements Filter{
    protected FilterConfig filterConfig = null;
    public void init(FilterConfig filterConfig)throws ServletException{
    this.filterConfig = filterConfig;
    }
    public void destroy(){
    this.filterConfig = null;
    }
    public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain)
    throws IOException, ServletException {
    try{
    chain.doFilter(request, response);
    }
    finally{
    try{
    HibernateSessionUtil.commitTransaction();
    }catch (InfrastructureException e){
    HibernateSessionUtil.rollbackTransaction();
    }finally{
    HibernateSessionUtil.closeSession();
    }
    }
    }
    }
    ---------------------------------------------------------------------------------------
    
          (1)、悲觀鎖定(Pessimistic Locking)一如其名稱所示,悲觀的認(rèn)定每次資料存取時(shí),其它的客戶端也會(huì)存取同一筆資料,因此對(duì)該筆資料進(jìn)行鎖定,直到自己操作完成後解除鎖定。 

          悲觀鎖定通常透過系統(tǒng)或資料庫(kù)本身的功能來實(shí)現(xiàn),依賴系統(tǒng)或資料庫(kù)本身提供的鎖定機(jī)制,Hibernate即是如此,可以利用Query或 Criteria的setLockMode()方法來設(shè)定要鎖定的表或列(Row)及其鎖定模式,可設(shè)定的鎖定模式有以下的幾個(gè):
  • LockMode.WRITE:在insert或update時(shí)進(jìn)行鎖定,Hibernate會(huì)在save()方法時(shí)自動(dòng)獲得鎖定。
  • LockMode.UPGRADE:利用SELECT ... FOR UPDATE進(jìn)行鎖定。
  • LockMode.UPGRADE_NOWAIT:利用SELECT ... FOR UPDATE NOWAIT進(jìn)行鎖定,在Oracle環(huán)境下使用。
  • LockMode.READ:在讀取記錄時(shí)Hibernate會(huì)自動(dòng)獲得鎖定。
  • LockMode.NONE:沒有鎖定。

          (2)、樂觀鎖定(Optimistic locking)則樂觀的認(rèn)為資料的存取很少發(fā)生同時(shí)存取的問題,因而不作資料庫(kù)層次上的鎖定,為了維護(hù)正確的資料,樂觀鎖定使用應(yīng)用程式上的邏輯實(shí)現(xiàn)版本控制的解決。 

          在不實(shí)行悲觀鎖定策略的情況下,資料不一致的情況一但發(fā)生,有幾個(gè)解決的方法,一種是先更新為主,一種是後更新的為主,比較複雜的就是檢查發(fā)生變動(dòng)的資料來實(shí)現(xiàn),或是檢查所有屬性來實(shí)現(xiàn)樂觀鎖定。
          要注意的是,由於樂觀鎖定是使用系統(tǒng)中的程式來控制,而不是使用資料庫(kù)中的鎖定機(jī)制,因而如果有人特意自行更新版本訊息來越過檢查,則鎖定機(jī)制就會(huì)無效,例如在上例中自行更改userV2的version屬性,使之與資料庫(kù)中的版本號(hào)相同的話就不會(huì)有錯(cuò)誤,像這樣版本號(hào)被更改,或是由於資料是由外部系統(tǒng)而來,因而版本資訊不受控制時(shí),鎖定機(jī)制將會(huì)有問題,設(shè)計(jì)時(shí)必須注意。

  • posted @ 2008-01-10 11:40 靈! 閱讀(272) | 評(píng)論 (0)編輯 收藏

    持久層的組成(轉(zhuǎn))

    持久層的組成
        這一節(jié)的名字應(yīng)該換成“基于Hibernate的持久層的組成”更合適一點(diǎn),可是它太長(zhǎng)了。既然Hibernate是用來開發(fā)持久層,那么我先介紹一下這個(gè)持久層中的各個(gè)元素。
    1.    POJO:Plain Old Java Object,你可以把它看作是簡(jiǎn)單的JavaBean。一般說來,一張數(shù)據(jù)庫(kù)表對(duì)應(yīng)一個(gè)POJO,也就是對(duì)象/關(guān)系的一一映射。
    2.    DAO:對(duì)于每一個(gè)POJO,一般都有一個(gè)DAO與之對(duì)應(yīng),承擔(dān)所有關(guān)于該P(yáng)OJO的訪問控制。實(shí)際上也就是控制了對(duì)數(shù)據(jù)庫(kù)中一張表的訪問控制。
    3.    *.hbm.xml文件:這個(gè)文件定義了POJO和數(shù)據(jù)庫(kù)中的表是如何映射的,比如POJO中的字段對(duì)應(yīng)數(shù)據(jù)庫(kù)表中的哪個(gè)字段等等。一般每個(gè)映射都用單獨(dú)的文件來描述,也就是有一個(gè)POJO就有一個(gè)*.hbm.xml文件。
    4.    *.cfg.xml文件:這個(gè)文件定義了Hibernate的基本信息,比如數(shù)據(jù)庫(kù)驅(qū)動(dòng),用戶名,密碼等等連接信息,也包括了所有要用的*.hbm.xml文件,在初始化的時(shí)候,Hibernate會(huì)讀取這個(gè)文件來找相應(yīng)的映射文件完成對(duì)象/關(guān)系。
    我們還是以上文的例子來詳細(xì)描述一下這里提到的各個(gè)元素的內(nèi)容。
    1.    Student.java:
    代碼片段4:
    1. public class Student  implements java.io.Serializable 
    2. {
    3.     private String id;
    4.     private String name;
    5.     private Set courseSelections = new HashSet(0);
    6.     public Student() 
    7.     {
    8.     }
    9.     public String getId() 
    10.     {
    11.         return this.id;
    12.     }
    13.     
    14.     public void setId(String id) 
    15.     {
    16.         this.id = id;
    17.     }
    18.     public String getName() 
    19.     {
    20.         return this.name;
    21.     }
    22.     
    23.     public void setName(String name) 
    24.     {
    25.         this.name = name;
    26.     }
    27.     public Set getCourseSelections() 
    28.     {
    29.         return this.courseSelections;
    30.     }
    31.     
    32.     public void setCourseSelections(Set courseSelections) 
    33.     {
    34.         this.courseSelections = courseSelections;
    35.     }
    36. }

    這個(gè)類就是一個(gè)POJO,你可以很明顯的看出來它就是一個(gè)JavaBean。我想解釋它的courseSelection字段。很顯然,在數(shù)據(jù)庫(kù)表student中,沒有這個(gè)字段。這里的這個(gè)字段是因?yàn)橐粋€(gè)外鍵引用,course_selection的student_id是一個(gè)外鍵,引用了student表中的id字段。那么在Student類中courseSelection來記錄這樣的外鍵關(guān)系,也就是說,當(dāng)我們獲取了Student對(duì)象以后,就可以直接獲取他的選課記錄,這樣就為上層的調(diào)用提供了很大的方便。這里有點(diǎn)模糊沒關(guān)系,我在介紹映射定義文件(*.hbm.xml)的時(shí)候還會(huì)提到這個(gè)問題。
    2.    StudentDAO.java
    代碼片段5:
    1. public class StudentDAO 
    2. {
    3.     Session session;
    4.     public StudentDAO()
    5.     {
    6.         Configuration cfg = new Configuration();
    7.         cfg.configure("/hibernate.cfg.xml");
    8.         SessionFactory sessionFactory = cfg.buildSessionFactory();
    9.         session = sessionFactory.openSession();
    10.     }
    11.     
    12.     public void save(Student transientInstance) 
    13.     {
    14.         session.save(transientInstance);
    15.     }
    16.     
    17.     public void delete(Student persistentInstance) 
    18.     {
    19.         session.delete(persistentInstance);
    20.     }
    21.     
    22.     public Student findById(java.lang.String id) 
    23.     {
    24.         List list = session.createCriteria(Student.class).add(
    25. Expression.eq("id", id)).list();
    26.         if (list.size() > 0) 
    27.         {
    28.             return (Student)list.get(0);
    29.         }
    30.         return null;
    31.     }
    32. }

    這里的構(gòu)造函數(shù)是用來啟動(dòng)Hibernate,并獲取session。打開一個(gè)session就相當(dāng)于打開了一個(gè)數(shù)據(jù)庫(kù)連接,然后我們就可以對(duì)這個(gè)session進(jìn)行操作,完成數(shù)據(jù)庫(kù)操作,完全不用寫SQL語句。我這里Hibernate的啟動(dòng)方式寫的很不規(guī)范,系統(tǒng)應(yīng)該只需要完成一次Hibernate啟動(dòng)就可以在不同的DAO中使用,我把它寫在構(gòu)造函數(shù)里面純粹是為了簡(jiǎn)化演示代碼。
    你可以看到save和delete方法都很簡(jiǎn)單直接對(duì)對(duì)象操作,而findById就有些麻煩,因?yàn)檫@里有一個(gè)查詢過程在里面。Hibernate里面查詢可以用Criteria這個(gè)類來完成,我們也常用Hibernate獨(dú)有的HQL(Hibernate Query Language)來完成查詢。當(dāng)然Hibernate也是支持原生SQL的。關(guān)于查詢的詳細(xì)信息請(qǐng)參考其他文章或書籍,我只是演示一個(gè)流程,介紹一些概念。
    3.    Student.hbm.xml
    代碼片段6:
    1. <hibernate-mapping>
    2.     <class name="Student" table="STUDENT">
    3.         <id name="id" type="string">
    4.             <column name="ID" length="10" />
    5.             <generator class="assigned" />
    6.         </id>
    7.         <property name="name" type="string">
    8.             <column name="NAME" not-null="true" />
    9.         </property>
    10.         <set name="courseSelections" inverse="true">
    11.             <key>
    12.                 <column name="STUDENT_ID" length="10" 
    13. not-null="true" />
    14.             </key>
    15.             <one-to-many class="CourseSelection" />
    16.         </set>
    17.     </class>
    18. </hibernate-mapping>

    這個(gè)文件定義了Student類和Student表是如何映射的。class元素定義了Sudent類和STUDENT表映射,然后就定義了各個(gè)屬性是如何映射的。如果一個(gè)屬性是數(shù)據(jù)庫(kù)的key,那么會(huì)用id標(biāo)簽來定義,column定義了當(dāng)前類的屬性和數(shù)據(jù)庫(kù)中的哪個(gè)字段對(duì)應(yīng),generator是id特有的。一般來說id是自增的,由于我的數(shù)據(jù)庫(kù)是用的Oracle,它沒有自增字段,要實(shí)現(xiàn)自增必須用Sequence,這超出了本文的范圍,所以我就用assigned來簡(jiǎn)化示例代碼。assigned表示id是用戶給定的。
    有一個(gè)比較特別的標(biāo)簽是set,它對(duì)應(yīng)著數(shù)據(jù)庫(kù)中的外鍵關(guān)系,上文我提到的通過Student對(duì)象可以獲得所有相關(guān)的選課記錄就是通過這里的定義實(shí)現(xiàn)的。name屬性對(duì)應(yīng)了Student類中的字段名,key表示哪個(gè)字段是外鍵,one-to-many表示Student和CourseSelection是一對(duì)多關(guān)系,這和事實(shí)相符。類似的還有many-to-one,many-to-many,不過這些都不常用,我不介紹了。Hibernate根據(jù)這個(gè)映射定義文件,在實(shí)例化一個(gè)POJO(比如Student)的時(shí)候,會(huì)自動(dòng)的把定義過映射的屬性用數(shù)據(jù)庫(kù)中的數(shù)據(jù)填充,set也包括在內(nèi)。
    4.    hibernate.cfg.xml
    代碼片段7:
    1. <hibernate-configuration>
    2.     <session-factory>
    3.         <property name="connection.username">test</property>
    4.         <property name="connection.url">
    5. jdbc:oracle:thin:@10.85.33.199:1521:glee</property>
    6.         <property name="dialect">
    7. org.hibernate.dialect.Oracle9Dialect</property>
    8.         <property name="connection.password">test</property>
    9.         <property name="connection.driver_class">
    10. oracle.jdbc.OracleDriver</property>
    11.         <mapping resource="Student.hbm.xml"></mapping>
    12.         <mapping resource="CourseSelection.hbm.xml"></mapping>
    13.         <mapping resource="Course.hbm.xml"></mapping>
    14.     </session-factory>
    15. </hibernate-configuration>

    這個(gè)文件我不解釋了,自己看吧。結(jié)合上文StudentDAO的例子,我想你應(yīng)該能看明白。
    看了這么多,或許你會(huì)有點(diǎn)頭皮發(fā)麻,POJO,DAO,配置文件...好像要寫的東西還是很多。值得慶幸的是現(xiàn)在Hibernate已經(jīng)發(fā)展的比較成熟了,有很多工具來幫助我們完成這些工作,比如MiddleGen,Hibernate Synchronizer等等。我使用的開發(fā)工具是Eclipse+MyEclipse,我所要做的只是把數(shù)據(jù)庫(kù)表建好,然后MyEclipse提供的工具會(huì)自動(dòng)根據(jù)數(shù)據(jù)庫(kù)表生成POJO,DAO,*.hbm.xml,甚至hibernate.cfg.xml都是自動(dòng)完成的(前提是MyEclipse知道你的數(shù)據(jù)庫(kù)連接信息)。我并不打算介紹如何用IDE來開發(fā)Hibernate,你可以參考IDE的幫助文檔。
    到這里為止,使用Hibernate進(jìn)行開發(fā)的基本組成元素我都介紹好了,強(qiáng)烈建議你馬上實(shí)踐一遍,即使有些不理解,也先依葫蘆畫瓢一個(gè)。對(duì)了,別忘了把Hibernate的包down下來放到classpath里面。

    三、Session與SessionFactory
    Session可以說是Hibernate的核心,Hibernate對(duì)外暴露的接口就是Session。所以我這里講一下有關(guān)Session的常用函數(shù)和特性。
    在講Session之前,我想先提一下SessionFactory,這個(gè)東西不復(fù)雜,只要配置好就行了。顧名思義,SessionFactory就是用來創(chuàng)建Session的。SessionFactory是線程安全的,也就是說對(duì)于同一個(gè)數(shù)據(jù)庫(kù)的所有操作共享一個(gè)SessionFactory就行了。回頭看代碼片段5,我們可以看到SessionFactory的常用配置方式。
    代碼片段8:
    1. Configuration cfg = new Configuration();
    2. cfg.configure("/hibernate.cfg.xml");
    3. SessionFactory sessionFactory = cfg.buildSessionFactory();

    我們通過Configuration來讀取配置文件,然后就可以創(chuàng)建SessionFactory,這段代碼在    所有系統(tǒng)中都大同小異,一般就是xml配置文件的名字不一樣,所以也沒什么好說的。
    當(dāng)我們有了SessionFactory以后就可以獲取Session了。調(diào)用SessionFactory.openSession()就會(huì)返回一個(gè)Session實(shí)例,然后我們操作這個(gè)Session來訪問數(shù)據(jù)庫(kù)。值得一提的是Session并不是線程安全的,也就是每一個(gè)線程都必須有自己的Session。所以我們一般通過以下方法來獲取和關(guān)閉Session:
    代碼片段9:
    1. public static Session currentSession() throws HibernateException 
    2.     {
    3.         Session session = (Session) threadLocal.get();
    4.         if (session == null || !session.isOpen()) 
    5.         {
    6.             if (sessionFactory == null
    7.             {
    8.                 try 
    9.                 {
    10.                     cfg.configure(CONFIG_FILE_LOCATION);
    11.                     sessionFactory = cfg.buildSessionFactory();
    12.                 } 
    13.                 catch (Exception e) 
    14.                 {
    15.                     e.printStackTrace();
    16.                 }
    17.             }
    18.             session = (sessionFactory != null) ?
    19.                  sessionFactory.openSession(): null;
    20.             threadLocal.set(session);
    21.         }
    22.         return session;
    23. }
    24. public static void closeSession() throws HibernateException 
    25.     {
    26.         Session session = (Session) threadLocal.get();
    27.         threadLocal.set(null);
    28.         if (session != null
    29.         {
    30.             session.close();
    31.         }
    32. }

    可以看到,我們通過threadLocal來保存每個(gè)線程的session,這樣就保證了各個(gè)線程之    間的互不干擾,也保證了系統(tǒng)只有一個(gè)SessionFactory實(shí)例(對(duì)于大多數(shù)應(yīng)用來說已經(jīng)    足夠了)。如果你使用MyEclipse進(jìn)行開發(fā)的話,它會(huì)自動(dòng)生成一個(gè)    HibernateSessionFactory.java,其中就包含了以上代碼。
    好了,現(xiàn)在我們已經(jīng)獲得了Session,下面我來介紹以下Session的常用函數(shù),這些函數(shù)都有很多重載函數(shù),我只介紹以下大概是干嘛的,不一一解釋,詳細(xì)信息你可以查看Hibernate的API。
    1.Session.get(),獲取某個(gè)類的實(shí)例,一般都是通過id來獲取比如
    Session.get(Student.class, "0361095");
    這句話的意思就是獲取id(primary key)為“0361095”的Student對(duì)象。這里要注    意的是第二個(gè)參數(shù)必須是Object,也就是說,如果是long類型的1,那么必須轉(zhuǎn)換    成new Long(1)再傳入。
    2.Session.load(),用法和意義都和get一樣,不過它們還是有點(diǎn)區(qū)別,我稍后解釋。
    3.Session.save(),將某個(gè)實(shí)例保存到數(shù)據(jù)庫(kù)中去(往往在數(shù)據(jù)庫(kù)中形成一條新的記錄)。
    4.Session.update(),更新某個(gè)實(shí)例,這個(gè)實(shí)例必須和數(shù)據(jù)庫(kù)中有對(duì)應(yīng),否則會(huì)報(bào)錯(cuò)。
    5.Session.delete(),刪除某個(gè)實(shí)例,也就是刪除這個(gè)實(shí)例對(duì)應(yīng)的數(shù)據(jù)表中的數(shù)據(jù)。
    6.Session.saveOrUpdate(),保存或者更新某個(gè)實(shí)例,調(diào)用這個(gè)方法你就不用去關(guān)心到        底是save還是update了,它會(huì)自己判斷,然后調(diào)用相應(yīng)的函數(shù)。其實(shí)save和update        涉及到實(shí)體對(duì)象生命周期中的三種狀態(tài),這個(gè)比較重要,我在后面會(huì)單獨(dú)講的。
    對(duì)于get和load的區(qū)別,很難講清楚,這里涉及到Hibernate的緩存機(jī)制,是一個(gè)非常    復(fù)雜的話題,我不打算深入討論這個(gè)內(nèi)容。簡(jiǎn)單的來講,Session實(shí)現(xiàn)了Hibernate的一    級(jí)緩存,SessionFactory實(shí)現(xiàn)了Hibernate的二級(jí)緩存。load方法會(huì)先查找一級(jí)緩存再查    找二級(jí)緩存,最后再去數(shù)據(jù)庫(kù)中找,而get只會(huì)查找一級(jí)緩存,然后就去數(shù)據(jù)庫(kù)中找了。    這只是是get和load的一個(gè)區(qū)別,另外的區(qū)別如果你有興趣的話自己去google吧。關(guān)于Hibernate的緩存機(jī)制,如果你只是一般用用Hibernate的話沒有必要深入研究,就當(dāng)它不存在好了,get和load到底用哪個(gè)也不用非常講究,如果你用工具生成DAO的話,    生成的代碼用什么就用什么吧。

    四、關(guān)鍵概念的理解
    在使用Hibernate進(jìn)行開發(fā)的時(shí)候有幾個(gè)概念在我看來是必須理解的,否則在開發(fā)的時(shí)候會(huì)遇到很多問題而摸不著頭腦。
    1.Lazy loading,懶加載(延遲加載)
    這個(gè)技術(shù)在很多地方被應(yīng)用,比如Eclipse的插件管理也是用的延遲加載。在Hibernate中,所謂延遲加載就是返回一個(gè)POJO但是某些數(shù)據(jù)(往往是實(shí)體類型或者Set類型)并沒有被真正的被填充,直到POJO的某個(gè)字段真正被引用的時(shí)候才從數(shù)據(jù)庫(kù)中讀取相應(yīng)的數(shù)據(jù)來填充POJO中的字段。這樣就能有效的避免很多不必要的數(shù)據(jù)庫(kù)操作,因?yàn)镻OJO的有些數(shù)據(jù)我們并不需要,而且數(shù)據(jù)庫(kù)操作是很費(fèi)時(shí)間的。在Hibernate2中,默認(rèn)是非延遲加載的,而在Hibernate3中,默認(rèn)就是延遲加載了。
    如果使用了延遲加載,那么在讀取數(shù)據(jù)的時(shí)候有一個(gè)問題必須注意,那就是在數(shù)據(jù)真正被加載之前,Session不能被關(guān)閉。你可以回頭看一下代碼片段5,我在構(gòu)造函數(shù)里面open了session以后就沒有關(guān)閉這個(gè)session,所以我在使用的時(shí)候沒有什么問題,但這樣總占著數(shù)據(jù)庫(kù)連接也不好,用好了應(yīng)該及時(shí)關(guān)閉給別人用。我上文給的例子中沒有關(guān)閉Session的代碼,要加的話給DAO加一個(gè)方法調(diào)用Session.close(),然后在代碼片段1中的return之前調(diào)用這個(gè)方法就行了。
    Hibernate的延遲加載機(jī)制遠(yuǎn)不是這么簡(jiǎn)單,但是普通的應(yīng)用沒有必要去深究這些東西,了解這么多就夠了。

    2. Object lifecycle,對(duì)象生命周期
    在Hibernate中,對(duì)象分為三種狀態(tài),Transient(自由狀態(tài))、Persistent(持久狀態(tài)),Detached(游離狀態(tài)),下面我分別解釋一下。
    1、自由狀態(tài):所謂自由狀態(tài)就是說這個(gè)對(duì)象是自由的,與Hibernate無關(guān),比       如:
    Student student = new Student();
        student.setId("0361095");
                    這里的student就是一個(gè)普通的對(duì)象與hibernate無關(guān),稱為自由狀態(tài)。

    2、持久狀態(tài):所謂持久狀態(tài)就是指對(duì)象和數(shù)據(jù)庫(kù)中的數(shù)據(jù)(持久狀態(tài)的數(shù)據(jù))       有關(guān)聯(lián),也就是說對(duì)象被Hibernate所管理了,比如:
    session.save(student);
       這樣student對(duì)象就從自由狀態(tài)變?yōu)槌志脿顟B(tài)了。持久狀態(tài)的對(duì)象在Session       與數(shù)據(jù)庫(kù)中的數(shù)據(jù)進(jìn)行同步時(shí)(比如commit)會(huì)把數(shù)據(jù)更新到數(shù)據(jù)庫(kù)。而         其他狀態(tài)的則不會(huì)。我覺得可以這樣來理解持久狀態(tài),可以看成Hibernate       也擁有一份對(duì)象的引用,那么如果你對(duì)持久狀態(tài)對(duì)象的屬性進(jìn)行更改的話,       Hibernate看到的對(duì)象的狀態(tài)也更改了,而Hibernate所看到的對(duì)象和數(shù)據(jù)       庫(kù)中的數(shù)據(jù)是等價(jià)的。也正是這樣,Hibernate才實(shí)現(xiàn)了Object/Relation       的映射。類似的,load和get方法也一樣會(huì)獲取Persistent狀態(tài)的對(duì)象。

    3、游離狀態(tài):每次調(diào)用Session.close以后,所有跟這個(gè)session有關(guān)的處于
    Persistant的對(duì)象就變成了游離狀態(tài)。也許你要問Detached和Transient有什么區(qū)別。其實(shí)從我給的例子來說看不出什么區(qū)別,因?yàn)槲疫@里ID是給定的,而真正開發(fā)的時(shí)候ID往往是自增的,那么Transient的對(duì)象是沒有ID    的,當(dāng)save了以后就有了,顯而易見Detached的對(duì)象也是有ID,只不過這個(gè)對(duì)象已經(jīng)和Hibernate脫離了關(guān)系。但是游離狀態(tài)的對(duì)象仍然和數(shù)據(jù)庫(kù)    中的記錄有一定聯(lián)系,至少游離狀態(tài)的對(duì)象知道數(shù)據(jù)庫(kù)中有條記錄的ID為xxx。從這一點(diǎn)上來講,游離狀態(tài)是可以自己創(chuàng)造出來的,只要你知道數(shù)據(jù)庫(kù)中的主鍵信息。
    在使用Hibernate開發(fā)的時(shí)候要分清楚這三種狀態(tài),否則很容易出錯(cuò)。比如不能去save一個(gè)游離狀態(tài)的對(duì)象,不能去update一個(gè)自由狀態(tài)的對(duì)象等等。

    五、結(jié)束語
    我要講的就這么多,這篇文章不是詳細(xì)介紹Hibernate,我只是總結(jié)了自己學(xué)習(xí)和使用Hibernate的一些感受和經(jīng)驗(yàn),希望能給沒有用過Hibernate的開發(fā)者一個(gè)上手的指引。如果你看完了這篇文章仍然滿頭霧水,無從下手的話,我只能向你表示歉意,浪費(fèi)你的時(shí)間了。不管怎樣,我強(qiáng)烈推薦一本書《深入淺出Hibernate》,這本書既能作為學(xué)習(xí)的教程,也能作為日后的查詢用書,相當(dāng)實(shí)用。

    posted @ 2008-01-10 11:39 靈! 閱讀(305) | 評(píng)論 (0)編輯 收藏

    JAVA數(shù)據(jù)類型轉(zhuǎn)換

    基本類型有以下四種:
    int長(zhǎng)度數(shù)據(jù)類型有:byte(8bits)、short(16bits)、int(32bits)、long(64bits)、
    float長(zhǎng)度數(shù)據(jù)類型有:?jiǎn)尉龋?2bits float)、雙精度(64bits double)
    boolean類型變量的取值有:ture、false
    char數(shù)據(jù)類型有:unicode字符,16位
    對(duì)應(yīng)的類類型:
    Integer、Float、Boolean、Character、Double、Short、Byte、Long


    轉(zhuǎn)換原則:
    從低精度向高精度轉(zhuǎn)換
    byte 、short、int、long、float、double、char
    注:兩個(gè)char型運(yùn)算時(shí),自動(dòng)轉(zhuǎn)換為int型;當(dāng)char與別的類型運(yùn)算時(shí),也會(huì)先自動(dòng)轉(zhuǎn)換為int型的,再做其它類型的自動(dòng)轉(zhuǎn)換

    基本類型向類類型轉(zhuǎn)換

    正向轉(zhuǎn)換:
    通過類包裝器來new出一個(gè)新的類類型的變量
    Integer a= new Integer(2);

    反向轉(zhuǎn)換:
    通過類包裝器來轉(zhuǎn)換
    int b=a.intValue();
    類類型向字符串轉(zhuǎn)換


    正向轉(zhuǎn)換:
    因?yàn)槊總€(gè)類都是object類的子類,而所有的object類都有一個(gè)toString()函數(shù),所以通過toString()函數(shù)來轉(zhuǎn)換即可

    反向轉(zhuǎn)換:
    通過類包裝器new出一個(gè)新的類類型的變量
    eg1: int i=Integer.valueOf(“123”).intValue()
    說明:上例是將一個(gè)字符串轉(zhuǎn)化成一個(gè)Integer對(duì)象,然后再調(diào)用這個(gè)對(duì)象的intValue()方法返回其對(duì)應(yīng)的int數(shù)值。
    eg2: float f=Float.valueOf(“123”).floatValue()
    說明:上例是將一個(gè)字符串轉(zhuǎn)化成一個(gè)Float對(duì)象,然后再調(diào)用這個(gè)對(duì)象的floatValue()方法返回其對(duì)應(yīng)的float數(shù)值。
    eg3: boolean b=Boolean.valueOf(“123”).booleanValue()
    說明:上例是將一個(gè)字符串轉(zhuǎn)化成一個(gè)Boolean對(duì)象,然后再調(diào)用這個(gè)對(duì)象的booleanValue()方法返回其對(duì)應(yīng)的boolean數(shù)值。
    eg4:Double d=Double.valueOf(“123”).doubleValue()
    說明:上例是將一個(gè)字符串轉(zhuǎn)化成一個(gè)Double對(duì)象,然后再調(diào)用這個(gè)對(duì)象的doubleValue()方法返回其對(duì)應(yīng)的double數(shù)值。
    eg5: long l=Long.valueOf(“123”).longValue()
    說明:上例是將一個(gè)字符串轉(zhuǎn)化成一個(gè)Long對(duì)象,然后再調(diào)用這個(gè)對(duì)象的longValue()方法返回其對(duì)應(yīng)的long數(shù)值。
    eg6: char=Character.valueOf(“123”).charValue()
    說明:上例是將一個(gè)字符串轉(zhuǎn)化成一個(gè)Character對(duì)象,然后再調(diào)用這個(gè)對(duì)象的charValue()方法返回其對(duì)應(yīng)的char數(shù)值。


    基本類型向字符串的轉(zhuǎn)換

    正向轉(zhuǎn)換:
    如:int a=12;
    String b;
    b=a+””;

    反向轉(zhuǎn)換:
    通過類包裝器
    eg1:
    int i=Integer.parseInt(“123”)
    說明:此方法只能適用于字符串轉(zhuǎn)化成整型變量
    eg2: float f=Float.valueOf(“123”).floatValue()
    說明:上例是將一個(gè)字符串轉(zhuǎn)化成一個(gè)Float對(duì)象,然后再調(diào)用這個(gè)對(duì)象的floatValue()方法返回其對(duì)應(yīng)的float數(shù)值。
    eg3: boolean b=Boolean.valueOf(“123”).booleanValue()
    說明:上例是將一個(gè)字符串轉(zhuǎn)化成一個(gè)Boolean對(duì)象,然后再調(diào)用這個(gè)對(duì)象的booleanValue()方法返回其對(duì)應(yīng)的boolean數(shù)值。
    eg4:Double d=Double.valueOf(“123”).doubleValue()
    說明:上例是將一個(gè)字符串轉(zhuǎn)化成一個(gè)Double對(duì)象,然后再調(diào)用這個(gè)對(duì)象的doubleValue()方法返回其對(duì)應(yīng)的double數(shù)值。
    eg5: long l=Long.valueOf(“123”).longValue()
    說明:上例是將一個(gè)字符串轉(zhuǎn)化成一個(gè)Long對(duì)象,然后再調(diào)用這個(gè)對(duì)象的longValue()方法返回其對(duì)應(yīng)的long數(shù)值。
    eg6: char=Character.valueOf(“123”).charValue()
    說明:上例是將一個(gè)字符串轉(zhuǎn)化成一個(gè)Character對(duì)象,然后再調(diào)用這個(gè)對(duì)象的charValue()方法返回其對(duì)應(yīng)的char數(shù)值。

    posted @ 2008-01-10 11:38 靈! 閱讀(256) | 評(píng)論 (0)編輯 收藏

    java 數(shù)據(jù)庫(kù)基本操作

    java 數(shù)據(jù)庫(kù)基本操作

      1、java數(shù)據(jù)庫(kù)操作基本流程

      2、幾個(gè)常用的重要技巧:

      ·可滾動(dòng)、更新的記錄集

      ·批量更新

      ·事務(wù)處理

      java數(shù)據(jù)庫(kù)操作基本流程:取得數(shù)據(jù)庫(kù)連接 - 執(zhí)行sql語句 - 處理執(zhí)行結(jié)果 - 釋放數(shù)據(jù)庫(kù)連接

      1、取得數(shù)據(jù)庫(kù)連接

      1)用DriverManager取數(shù)據(jù)庫(kù)連接

      例子

      String className,url,uid,pwd;

      className = "oracle.jdbc.driver.OracleDriver";

      url = "jdbc:oracle:thin:@127.0.0.1:1521:orasvr;

      uid = "system";

      pwd = "manager";

      Class.forName(className);

      Connection cn = DriverManager.getConnection(url,uid,pwd);

      2)用jndi(java的命名和目錄服務(wù))方式

      例子

      String jndi = "jdbc/db";

      Context ctx = (Context) new InitialContext().lookup("java:comp/env");

      DataSource ds = (DataSource) ctx.lookup(jndi);

      Connection cn = ds.getConnection();

      多用于jsp中

      2、執(zhí)行sql語句

      1)用Statement來執(zhí)行sql語句

      String sql;

      Statement sm = cn.createStatement();

      sm.executeQuery(sql); // 執(zhí)行數(shù)據(jù)查詢語句(select)

      sm.executeUpdate(sql); // 執(zhí)行數(shù)據(jù)更新語句(delete、update、insert、drop等)statement.close();

      2)用PreparedStatement來執(zhí)行sql語句

      String sql;

      sql = "insert into user (id,name) values (?,?)";

      PreparedStatement ps = cn.prepareStatement(sql);

      ps.setInt(1,xxx);

      ps.setString(2,xxx);

      ...

      ResultSet rs = ps.executeQuery(); // 查詢

      int c = ps.executeUpdate(); // 更新

      3、處理執(zhí)行結(jié)果

      查詢語句,返回記錄集ResultSet

      更新語句,返回?cái)?shù)字,表示該更新影響的記錄數(shù)

      ResultSet的方法

      1、next(),將游標(biāo)往后移動(dòng)一行,如果成功返回true;否則返回false

      2、getInt("id")或getSting("name"),返回當(dāng)前游標(biāo)下某個(gè)字段的值

      4、釋放連接

      cn.close();

      一般,先關(guān)閉ResultSet,然后關(guān)閉Statement(或者PreparedStatement);最后關(guān)閉Connection

      可滾動(dòng)、更新的記錄集

      1、創(chuàng)建可滾動(dòng)、更新的Statement

      Statement sm = cn.createStatement(ResultSet.TYPE_SCROLL_ENSITIVE,ResultSet.CONCUR_READ_ONLY);

      該Statement取得的ResultSet就是可滾動(dòng)的

      2、創(chuàng)建PreparedStatement時(shí)指定參數(shù)

      PreparedStatemet ps = cn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);

      ResultSet.absolute(9000);

      ·批量更新

      1、Statement

      Statement sm = cn.createStatement();

      sm.addBatch(sql1);

      sm.addBatch(sql2);

      ...

      sm.executeBatch()

      一個(gè)Statement對(duì)象,可以執(zhí)行多個(gè)sql語句以后,批量更新。這多個(gè)語句可以是delete、update、insert等或兼有

      2、PreparedStatement

      PreparedStatement ps = cn.preparedStatement(sql);

      {

      ps.setXXX(1,xxx);

      ...

      ps.addBatch();

      }

      ps.executeBatch();

      一個(gè)PreparedStatement,可以把一個(gè)sql語句,變換參數(shù)多次執(zhí)行,一次更新。

      ·事務(wù)的處理

      1、關(guān)閉Connection的自動(dòng)提交

      cn.setAutoCommit(false);

      2、執(zhí)行一系列sql語句

      要點(diǎn):執(zhí)行每一個(gè)新的sql語句前,上一次執(zhí)行sql語句的Statement(或者PreparedStatemet)必須先close

      Statement sm ;

      sm = cn.createStatement(insert into user...);

      sm.executeUpdate();

      sm.close();

      sm = cn.createStatement("insert into corp...);

      sm.executeUpdate();

      sm.close();

      3、提交

      cn.commit();

      4、如果發(fā)生異常,那么回滾

      cn.rollback();

    posted @ 2008-01-10 11:37 靈! 閱讀(234) | 評(píng)論 (0)編輯 收藏

    <2008年1月>
    303112345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789

    導(dǎo)航

    統(tǒng)計(jì)

    隨筆分類

    隨筆檔案

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 亚洲国产精品VA在线看黑人| 亚洲国产精品激情在线观看| 亚洲美女免费视频| 免费无码又爽又刺激网站直播 | 成在人线av无码免费高潮喷水| 亚洲精品国产V片在线观看| 在线免费播放一级毛片| 中国亚洲女人69内射少妇| 亚洲黄片手机免费观看| 亚洲欧洲日产国码高潮αv| 国产精品福利在线观看免费不卡| 亚洲伊人久久综合影院| 中国人免费观看高清在线观看二区| 亚洲中文字幕无码久久2017| 国内精品久久久久影院免费| 亚洲av无码无在线观看红杏| 日本免费大黄在线观看| 亚洲va成无码人在线观看| 性一交一乱一视频免费看| 黄色免费网址在线观看| 亚洲精品色午夜无码专区日韩| 日本在线看片免费| 亚洲成人免费电影| 日韩激情淫片免费看| 色爽黄1000部免费软件下载| 亚洲精品蜜桃久久久久久| 91九色精品国产免费| 亚洲heyzo专区无码综合| 亚洲欧洲∨国产一区二区三区| 免费播放一区二区三区| 亚洲一区二区三区丝袜| 亚洲女同成人AⅤ人片在线观看| 无码国产精品一区二区免费3p| 亚洲妇女熟BBW| 中文字幕亚洲图片| 福利免费观看午夜体检区| 偷自拍亚洲视频在线观看| 亚洲国产高清人在线| 免费一看一级毛片| 182tv免费观看在线视频| 羞羞视频免费网站含羞草|