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

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

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

    javaGrowing

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      92 隨筆 :: 33 文章 :: 49 評(píng)論 :: 0 Trackbacks

    #

         摘要: Java 基礎(chǔ)方面 : ...  閱讀全文
    posted @ 2006-02-28 10:57 javaGrowing 閱讀(3620) | 評(píng)論 (15)編輯 收藏

    o_left-1.jpg o_right-1.jpg
    posted @ 2006-02-08 11:45 javaGrowing 閱讀(233) | 評(píng)論 (0)編輯 收藏

    JDBC高級(jí)應(yīng)用三

    再談JDBC連結(jié)

    為什么要反復(fù)談JDBC連結(jié),因?yàn)樗訨DBC的性能,最主要的就是JDBC連結(jié),而SQL語句的
    優(yōu)化,和JAVA編程無關(guān),你的一個(gè)查詢語句的效率,是你對(duì)于SQL語法的使用技巧,這一方
    面你就可請(qǐng)教DBA,而不是來看我這種程序設(shè)計(jì)者的文章.

    我們已經(jīng)知道,取得數(shù)據(jù)庫連結(jié),有幾種層次的實(shí)現(xiàn)方法,一是直接得到物理連結(jié),而是通
    過傳統(tǒng)的連結(jié)池(沒有多大區(qū)別),三是通過java的擴(kuò)展包javax.sql.DataSource得到連結(jié)
    句柄,對(duì)于上面兩種,沒有什么可以多說的,對(duì)于DataSource,我們?cè)偕钊胍恍?
    一般來說,DataSource是容器本身作為一個(gè)JDNI查找的對(duì)象返回出來的,也就是說要依賴
    容器進(jìn)行配置,而如果一個(gè)100%的應(yīng)用程序(Application),比如基于swing的App,我根本
    不需要運(yùn)行容器,那我如何取得DataSource對(duì)象?這時(shí)可能要你自己寫基于DataSource的
    連結(jié)池了(是不是有些太深入了?要做就做高手,SUN能做我們就能做).
    如果自己要實(shí)現(xiàn)DataSource,要清楚幾個(gè)關(guān)系,即DataSource中返回的Connection是一個(gè)連
    結(jié)的句柄,它要和實(shí)際的物理連結(jié)關(guān)連,這些實(shí)際的物理連結(jié)就是PooledConnection,我們
    叫它池中的連結(jié),可以通過實(shí)現(xiàn)ConnectionPoolDataSource,從中得到PooledConnection,
    這部分本來是廠商實(shí)現(xiàn)的,但這部份實(shí)現(xiàn)和傳統(tǒng)的連結(jié)池沒有什么大的區(qū)別,主要是從
    ConnectionPoolDataSource中得到PooledConnection的物理連結(jié),但如何從PooledConnection
    中g(shù)etConnection(),返回給用戶.這部分實(shí)現(xiàn)就是DataSource實(shí)現(xiàn)的性能高低的關(guān)鍵,一般
    來說,我們可以先把一個(gè)物理連結(jié)PooledConnection和多個(gè)客戶連結(jié)相關(guān)連來增加性能,也
    就是一個(gè)PooledConnection本身再作為一個(gè)工場的種子,通過一個(gè)PooledConnection再返回
    多個(gè)Connection,說白了就是多個(gè)Connection的請(qǐng)求通過一個(gè)PooledConnection傳遞給數(shù)據(jù)庫.
    只要用戶調(diào)用Connection的close()方法,就打斷這個(gè)Connetion與PooledConnection的關(guān)聯(lián)而
    讓PooledConnection可以和新的Connection進(jìn)行關(guān)聯(lián).

    JDBC事務(wù)

    JDBC1開始,就支持本地事務(wù),所謂要地事務(wù),就是在一個(gè)連結(jié)中的多個(gè)操作可以作為一個(gè)事務(wù)
    過程來提交.注意,只要你使用conn.setAutoCommit(false);方法就隱式地打開了一個(gè)事務(wù).當(dāng)
    事務(wù)被commit或abort時(shí),隱含的是打開了一個(gè)新的事務(wù).
    另外,當(dāng)一次事務(wù)被commit或abort,PreparedSattement和CallableStatement綁定的結(jié)果集全
    部被關(guān)閉,而普通的Statement綁一的結(jié)果集將被維持.
    在處理多個(gè)操作時(shí):
    conn.setAutoCommit(false);
    Statement st1 = conn.createSatatement(sql1);
    Statement st2 = conn.createSatatement(sql2);
    Statement st3 = conn.createSatatement(sql3);
    Statement st4 = conn.createSatatement(sql4);
    st1.executeXXXXX();
    st2.executeXXXXX();
    st3.executeXXXXX();
    st4.executeXXXXX();
    在這里,我們要么把四個(gè)操作一起回滾,或一起提交,但如果我們認(rèn)為,1-3的操作是要求一致完
    成,而4的操作在一至三完成時(shí)再完成.在經(jīng)前的版本中我們要把它們分開在兩次事務(wù)中,但在
    JDBC3.0以后,我們可以利用conn.setSavepoint() 來得到一個(gè)SavePoint來對(duì)同一事務(wù)中不同階
    段進(jìn)行斷點(diǎn)保存.然后可以在任何斷點(diǎn)上進(jìn)行提交和回滾.同時(shí)我們還可以利用
    conn.setTransactionIsolation()來設(shè)置隔離級(jí)別.
    要注意的是,對(duì)事務(wù)的支持要看數(shù)據(jù)庫的具體實(shí)現(xiàn).如果數(shù)據(jù)庫本身不支持事務(wù),那么以上的操作
    都是無效的,可以從 DatabaseMetaData中查詢數(shù)據(jù)庫對(duì)事務(wù)的支持情況.

    畢竟,本地事務(wù)功能并不是很強(qiáng),而如果不是編程人員對(duì)SQL語句傳入錯(cuò)誤,那么在一次連結(jié)中
    多個(gè)操作只完成部份的機(jī)率并不容易發(fā)生(當(dāng)然有時(shí)還會(huì)發(fā)生的,要不本地事務(wù)就不會(huì)產(chǎn)生了).
    其實(shí),JDBC事務(wù)最重要的是分布式事務(wù),即同時(shí)操作不同的連結(jié),可能是同物理庫的不同空間,也
    可能是同一主機(jī)的不同數(shù)據(jù)庫或不同主機(jī)的多個(gè)數(shù)據(jù)庫.這就很難保證每個(gè)操作都是成功的,發(fā)
    生操作不一致的機(jī)會(huì)太多了,可以說如果不在事務(wù)中測試你就無法相信操作的一致性.所以分布
    式事務(wù)是JDBC的重要技術(shù).
    在下一節(jié)我們重點(diǎn)介紹JDBC分布式事務(wù).
    posted @ 2006-01-09 15:01 javaGrowing 閱讀(308) | 評(píng)論 (0)編輯 收藏

    JDBC高級(jí)應(yīng)用(二)
    本來想繼續(xù)談JDBC的高級(jí)連結(jié)方式,事務(wù)模式.但發(fā)現(xiàn)關(guān)于大對(duì)象存儲(chǔ)有很多人在問,所以
    先來插入一節(jié)關(guān)于大對(duì)象存儲(chǔ)的內(nèi)容,然后再接著原來的思路寫下去.

    JDBC的大對(duì)象存儲(chǔ)聽起來復(fù)雜,其實(shí)如果你明白了原理以后,就非常簡單,網(wǎng)上有關(guān)這方面的
    教材很少,而SUN的文檔中,我從1.2開始看到一在仍然是錯(cuò)誤的,不知道寫文檔的人長腦子沒
    有,就那幾行代碼你試試不就知道了,這么多次重抄下來還是錯(cuò)誤的.


    大對(duì)象分類:一般來說,大對(duì)象分為:大的文本對(duì)象,比如一個(gè)很長的文本(請(qǐng)你要注意什么是
    文本文件,什么是二進(jìn)制文件)文件,或者是你定義的一個(gè)長字符串,比如你定義了:
    String s = "我們要去吃飯了......................然后睡覺!";
    從吃飯到睡覺中間省略了實(shí)際的10000000000000字,雖然你不會(huì)真的定義這么稱的String,但
    有時(shí)會(huì)從什么地方得到這樣的String,要寫到數(shù)據(jù)庫中.
    另一種就是大的二進(jìn)制對(duì)象,象執(zhí)行文件,圖象文件等,注意,word,excel,ppt這些"帶格式"的文
    檔都應(yīng)該以二進(jìn)制對(duì)象存儲(chǔ).

    一般來說,數(shù)據(jù)庫如果支持大對(duì)象存儲(chǔ),會(huì)有這幾種類型的SQL數(shù)據(jù)類型:
    BLOB,CLOCB,NLOB,也有的數(shù)據(jù)數(shù)只有一種BLOB,基本上是這樣的:BLOB用來存放二進(jìn)制文件,而
    CLOB用來存放文本文件,NLOB是對(duì)多字節(jié)文本文件支持.假如你的文本文件是純英文的,放在
    BLOB中當(dāng)然可以,也就是說它是以byte格式存儲(chǔ)的,而多字節(jié)是以CHAR格式存儲(chǔ)的.

    同樣對(duì)于這幾種類型的文檔,有幾種相對(duì)應(yīng)的存取方式:
    setter:
    利用PreparedStatement的setXXX方法,
    setAsciiStream()方法用于寫入一般的文本流.setBinaryStream()方法用于寫入二進(jìn)制流
    而setUnicodeStream()用于寫好UNICODE編碼的文本,與此相對(duì)應(yīng)的ResultSet中三個(gè)getter方法
    用于取回:getAsciiStream(),getBinaryStream(),getBinaryStream().
    對(duì)于文件本身,要把它作為一個(gè)流,只要new InputStream(new FileInputStream("文件路徑"))
    就可以了,但對(duì)于大的String對(duì)象,你不會(huì)寫入文件再轉(zhuǎn)換成輸入流吧?
    new StringBufferInputStream(String s),記住了.
    JDBC2以后提供了java.sql.BLOB對(duì)象,我不建議大家使用它,一是很麻類,二是容易出錯(cuò),要先插
    入一個(gè)空的BLOB對(duì)象,然后再填充它,實(shí)在沒有必要,直接setXXX就行了,我試過,至少mysql,
    oracle,sql server是可以直接set的.
    好了,我們先看一個(gè)例子如何寫入文件到數(shù)據(jù)庫:
    數(shù)據(jù)結(jié)構(gòu):
    create table test(
      name varchar(200),
      content BLOB
    );
    File f = new File("a.exe");//先生成File對(duì)象是為了取得流的長度.FileInputStram可以直接
                               //傳入文件路徑
    InputStream in = new InputStream(new FileInputStream(f));
    PreparedStatement ps = conn.prepareStatement("insert into test (?,?)");
    ps.setString(1,"a.exe");
    ps.setBinaryStream(2,in,(int)f.length());
    ps.executeUpdate();
    f的長度一定要做從long到int的轉(zhuǎn)換,SUN的文檔中好幾版都沒有改過來.就這么簡單,當(dāng)然,不同的
    數(shù)據(jù)庫存本身要設(shè)置它允許的最大長度,MYSQL默認(rèn)只能傳1M的文件,要修改參數(shù)原能存更大的文件.
    如果要從數(shù)庫中取得文件:
    PreparedStatement ps = conn.prepareStatement("select * from test where name=?");
    ps.setString(1,"a.exe");
    ResultSet rs = ps.executeQuery();
    if(rs.next()){
     InputStream in = rs.getBinaryStream("content");
    }
    得到in對(duì)象后,你可以進(jìn)行任何處理,寫向文件和寫向頁面只是out對(duì)象不同而已:
    寫向文件:
    DateOutputStream out = new DateOutputStream(new FileOutputStream("b.exe"));
    寫向頁面:
    response.reset();
    response.setContType("類型");
    ServletOutputSreamt out = response.getOutputSream();
    得到out對(duì)象后,就可以輸出了:
    byte[] buf = new byte[1024];
    int len = 0;
    while((len = in.read(buf)) >0)
      out.write(buf,0,len);
    in.close();
    out.close();
    對(duì)于向頁面輸入,要設(shè)置什么樣的ContType,要看你想如何輸出,如果你想讓對(duì)方下載,就設(shè)為
    "application/octet-stream",這樣即使是文本,圖象都會(huì)下載而不會(huì)在瀏覽器中打開.如果你要想
    在瀏覽器中打開,就要設(shè)置相應(yīng)的類型,還要在容器的配置文件中設(shè)置支持這種文檔類型的輸出,但
    對(duì)于很多格式的文件,到底要輸出什么類型,其實(shí)就是HTTP的MIME集,比如圖片:image/gif,當(dāng)然你如
    果你的文件擴(kuò)展名(ext)不確定,你也不要用if(ext.equals("gif"))......這樣來判斷,我教你一個(gè)
    技巧,我之所以說是技巧,是我沒有在別的地方發(fā)現(xiàn)有人用這種方法,對(duì)我來說我是絕對(duì)不會(huì)把別人的
    方法拿來說是我的技巧的:
    構(gòu)造一個(gè)file類型的URL,我們知道URL目前JAVA可以支持HTTP,FTP,MAILTO,FILE,LDAP等,從FILE類型
    的URL就可以得到它的MIME:

    URL u = new URL("file://a.exe");
    String mime = u.openConnection().getContentType();
    這樣你就可以直接response.setContType(mime);而不用一個(gè)一個(gè)類型判斷了.
    好了,大對(duì)象存儲(chǔ)就說到這兒,不同的數(shù)據(jù)仍然和些特殊的規(guī)定,不在此一一列舉了.
    posted @ 2006-01-09 10:08 javaGrowing 閱讀(319) | 評(píng)論 (0)編輯 收藏

    JDBC高級(jí)應(yīng)用 一

    關(guān)于數(shù)據(jù)庫連結(jié)

    我們所說有JDBC高級(jí)應(yīng)用,并不是說它的技術(shù)含量很高(也許JAVA平臺(tái)上不存在什么"技術(shù)含量"的說
    法,因?yàn)镴AVA是給大家用的而不是給某些人用的).說它是高級(jí)應(yīng)用,是因?yàn)樗菍?duì)于JDBC基礎(chǔ)應(yīng)用來
    說的擴(kuò)展,也就是可以優(yōu)化你的應(yīng)用性能,或方便于應(yīng)用的實(shí)現(xiàn).所以說它是一種高級(jí)應(yīng)用而不叫高級(jí)
    技術(shù).

        JDBC中,java.sql包是基礎(chǔ)的,也是核心的功能,javax.sql包則是高級(jí)的,擴(kuò)展的功能.所以
    為了交流的方便,我們把它們區(qū)分為core API和optional API.

        但是仍然然有一些core API中的功能,我把它歸納到高級(jí)應(yīng)用中.象存儲(chǔ)過程的調(diào)用,多結(jié)果集
    的處理,我之所以要把這些東西拿出來說明,是目前你在網(wǎng)上找不到任何一份詳細(xì)的文檔和例程,可以
    說有95%以上的開發(fā)人員都不知道真正如何處理這些工作.所以我會(huì)在回上海后詳細(xì)寫這一段的內(nèi)容.
    現(xiàn)在我們還是來看看optional API給我們帶來的好處:

        我們已經(jīng)了解,執(zhí)行一個(gè)SQL語句,要經(jīng)過如下幾步:
        1.Connction
        2.Statement
        3.Statement.executeXXXXX();
        4.可選的對(duì)結(jié)果集的處理
        5.必要的Connction的關(guān)閉.(再次提醒如果你想成為中級(jí)水平以上的程序員,請(qǐng)你把關(guān)閉語
        句寫在finally塊中,在通過下面的介紹后我介紹一個(gè)方法可以用來驗(yàn)證你的程序是否有連結(jié)
        泄漏)
        
        這其中,生成Connction對(duì)象是最最重要的工作,也是最消耗資源的,因?yàn)檫B結(jié)對(duì)象要驅(qū)動(dòng)底層
    的SOCKET,調(diào)用物理連結(jié)和數(shù)據(jù)庫進(jìn)行通信,所以生成,關(guān)閉,再生成這種連結(jié)對(duì)象就相當(dāng)于我們?cè)诙?BR>世紀(jì)八十年代(1980年以后出身的不了解吧?)喝易拉罐飲料一樣.你買一瓶飲料是一塊二角錢,你可知道
    那罐子(Connection)值一塊零八分.而你喝下去的東西只值一角二分錢,這是我們那兒一個(gè)飲料廠的真實(shí)
    數(shù)據(jù).
        在javax.sql包出來以前,我們只能買這樣的飲料來喝,除非你不喝.也有一些人不服氣自己生
    產(chǎn)飲料(poolman),可是消費(fèi)者很快發(fā)現(xiàn),它只是把原來單賣的易拉罐現(xiàn)在打包賣給了我們,因?yàn)樗€是
    用原來的包裝原料來生產(chǎn)的,poolman這種類型的連結(jié)池,其根本是從DriverManager中g(shù)etConnection
    出來的.真正的效率如果不是你心理作用的話,也許比單個(gè)連結(jié)還要低!!!以及一些江湖好漢的"杰作",
    都無法跳出這個(gè)框框.我自己在那一段時(shí)間也曾醉心于研究這些"連結(jié)池",因?yàn)檎l都可以把別人的原碼
    讀過后,再加上其他人的優(yōu)點(diǎn)寫出一個(gè)更好的來,可是,大家可以看到,我寫出了好用的Upload,DownLoad,
    HtmlUtil,Encoder,Decoder等一系列工具.可是我沒有寫出成功的連結(jié)池.......

        我們?cè)賮砩钊胍徊?為什么DriverManager生成的連結(jié)和基于它的連結(jié)池不能真正提高性能.
    DriverManager對(duì)象中,絕大多數(shù)的JDBC是封裝了一個(gè)物理連結(jié),也就是它抓住了一個(gè)和數(shù)據(jù)庫通信的
    Socket,當(dāng)你使用DriverManager.getConnection()時(shí)也就是有一個(gè)和數(shù)據(jù)庫連結(jié)的Socket讓你占用了.
    而且這個(gè)方法是同步的.大家知道這樣的物理連結(jié)對(duì)于任何系統(tǒng)是有限制的,比如一個(gè)WEB服務(wù)器一般
    最大并發(fā)是150到250之間,數(shù)據(jù)庫服務(wù)器也是這樣的道理,你不僅要考慮你的程序不能用光連結(jié),還要
    考慮不同Runtime中或其它應(yīng)用程序也在同時(shí)和你一起使用這些物理連結(jié),如果一臺(tái)服務(wù)器上有JAVA 
    WEB SERVER,還有一個(gè)C的應(yīng)用程序也訪問數(shù)據(jù)庫,你不能那么無禮地要求人家C程序員他的程序必須
    等你的JAVA調(diào)用空閑才能訪問數(shù)據(jù)庫吧.所以物理連結(jié)是極其寶貴的.
        基于DriverManager.getConnection()的連結(jié)池只不過是預(yù)先生成這樣的物理連結(jié)放在一個(gè)
    pool中,然后編號(hào)等你調(diào)用,它省略的是生成這樣的連結(jié)的時(shí)間.注意你得到的連結(jié)在你沒有釋放之前,
    它無法處理別的工作,因?yàn)檫B結(jié)句柄在用戶手中,另外這種連結(jié)池調(diào)用時(shí)是由程序調(diào)用者初始化的,
    每一次調(diào)用都必須有初始化工作,而調(diào)用者是否以優(yōu)化的方法去運(yùn)行它,完成還要看每個(gè)人的編程水
    平.另一方面,如果這種連結(jié)池是如果用于WEB容器管理,那簡單是垃圾,因?yàn)樗鼜?qiáng)迫使用靜態(tài)變量來
    保持連結(jié),容器根本無法做到訪問控制.而且它不能在不同Runtime中被調(diào)用.

        而javax.sql的實(shí)現(xiàn)采用了在用戶連結(jié)和物理連結(jié)中間加一個(gè)緩沖的中間層,它雖然也只生
    成30個(gè)物理連結(jié),但用戶本身不能訪問它,DataSource返回給用戶的是一個(gè)JAVA抽象對(duì)象,客戶程序把
    連結(jié)請(qǐng)求放回緩沖中由DataSource統(tǒng)一調(diào)度物理連結(jié)來處理,這樣可以最大程序利用寶貴的物理連結(jié)
    也許現(xiàn)在的30個(gè)物理連結(jié)仍然不夠負(fù)載,你仍然需要修改實(shí)際連結(jié)數(shù),但我們知道,我們現(xiàn)在的這種連
    結(jié)方式已經(jīng)不是DriverManager.getConnection()能比的了.也就是說,在同樣多的物理連結(jié)下,
    DataSource可以給我們更多(是多得多的)的調(diào)用機(jī)會(huì),其實(shí),正常情況下一個(gè)從DriverManager中
    getConnection()出來物理連結(jié)的負(fù)載量只有百分之幾,就是因?yàn)槟愕恼{(diào)用抓住了它的句柄而不能讓
    它很好地工作.另外程序員只能返回它而不能關(guān)閉它,因?yàn)閭鹘y(tǒng)連結(jié)池中連結(jié)對(duì)象一旦由用戶關(guān)閉,
    就要再次重新生成物理新的連結(jié),所以用戶只能釋放,對(duì)于非連結(jié)池和連結(jié)池得到的連結(jié)對(duì)象,
    要用不同的代碼編程,簡單是一種痛苦.一旦沒有注意,在處理完數(shù)據(jù)后不是釋放而是關(guān)閉,這個(gè)錯(cuò)誤
    到底是誰的過錯(cuò)?????????????

        我上面說java.sql實(shí)現(xiàn)絕大多數(shù)是得到物理連結(jié),也有例外,但不是那些以前的連結(jié)池,而是
    OSE,就是oracle的servlet環(huán)境,它是把servlet服務(wù)器實(shí)現(xiàn)在數(shù)據(jù)庫的地址空間上,servlet服務(wù)去調(diào)
    用數(shù)據(jù)庫根本沒有通過傳統(tǒng)的連結(jié),因?yàn)閿?shù)據(jù)是"敞開"的,這就象通過網(wǎng)絡(luò)訪問其它計(jì)算機(jī)文件和訪問
    本地文件的區(qū)別. 雖然它也提供標(biāo)準(zhǔn)的JDBC接口讓你調(diào)用,但它底層根本不是用JDBC封裝的.

        DataSource的另外一個(gè)優(yōu)點(diǎn)就是它完全實(shí)現(xiàn)數(shù)據(jù)庫和應(yīng)用程序的分離,如何配置服務(wù)器生成
    DataSource的引用和程序開發(fā)無關(guān),你在程序開發(fā)中,只要通過JDNI查找DataSource的邏輯名稱就行.
    而DriverManager.getConnection()中,你不得不把數(shù)據(jù)庫驅(qū)動(dòng)程序名,訪問地址,用戶,密碼寫在你的
    應(yīng)用程序中,即使可以從配置文件中讀取這些屬性串,而不同的服務(wù)器配置文件的路徑你都要修改.而
    DataSource提供了標(biāo)準(zhǔn)的配置.

        說來說去,如何用DataSource來連結(jié)數(shù)據(jù)庫?

        非常簡單:

        DataSource ds = (DataSource)new InitialContext().lookup("jdbc/mydb");
        Connection conn = ds.getConnection();

        當(dāng)然我是為了說明它簡單故意把它的異常給忽略了.實(shí)際應(yīng)用中.你應(yīng)該捕獲它的異常.

        如果你還不明白什么是JDNI,我勸你先找一些這方面的資料看看,這可以是網(wǎng)編程方面的
    基礎(chǔ)協(xié)議啊.

        關(guān)于DataSource ds = (DataSource)new InitialContext().lookup("jdbc/mydb");有幾點(diǎn)
    需要說明的是,你只要配置好你的服務(wù)器(tomcat,resin,weblogic)這些服務(wù)器中都有一個(gè)例子,如果
    你不是很懂,你先把那個(gè)例子改動(dòng)幾個(gè)字就行了.用一段時(shí)間你就會(huì)慢慢理解它們代表什么了.
    然后你在容器環(huán)境下調(diào)用new InitialContext().lookup("jdbc/mydb")容器就會(huì)自動(dòng)找到那個(gè)
    DataSource對(duì)象給你調(diào)用,這個(gè)過程對(duì)用戶來說是透明的.
        那邊那個(gè)聰明的朋友已經(jīng)問了,因?yàn)镈ataSource的屬性是已經(jīng)配置好的放在容器中的,那我
    不在容器環(huán)境下,比如一個(gè)獨(dú)立的application,我如何能取到DataSource呢?
        其實(shí),如果你能知道new InitialContext()時(shí),容器調(diào)用了哪些默認(rèn)的配置,你就可以把
    這些配置參數(shù)手工加進(jìn)去而不依賴容器環(huán)境了.好在InitialContext可以getEnvironment() ,在生
    成這個(gè)對(duì)象后你可以get一下看看,把這些參數(shù)記下來,以后在沒有這些參數(shù)的環(huán)境下put進(jìn)去.
        這里多幾句話,談一下學(xué)習(xí)方法,我在國內(nèi)主持幾個(gè)論壇(不多,兩三個(gè)),從沒有問過別人什
    么問題,java技術(shù)又不是我發(fā)明的,不可能我什么都懂,一是問了好象有損于"高手"風(fēng)范(哈哈,其實(shí)
    真正的高手還是要問別人的,只有我這種假高手才不會(huì)問別人).另一方面是我根本不必問別人,比如
    象application下,連結(jié)不同廠家的DataSource要put什么東西進(jìn)去呢?一是去他們的網(wǎng)站看資料,雖然
    我的英語水平只有大家的10%,但我上英文網(wǎng)站的次數(shù)可能比你們多.二是看有沒有什么共用的API能
    得到,好在可以getEnvironment(),但假如沒有這個(gè)方法呢?這就要看你的學(xué)習(xí)態(tài)度了,有人會(huì)這論壇
    叫"高手球命",還有什么"急用,在線等待"什么的.而我,會(huì)把new InitialContext()反編譯出來看看
    它調(diào)用了什么(孔子說,為了學(xué)習(xí)的目的,反編譯是允許的,甚至說是偉大的,光明的,正確的思想,是有
    道德的,脫離了低級(jí)趣味的,有益于人民的行為!!!----孔子語錄補(bǔ)集第123頁第4行,1989年10月版)
    如果一個(gè)對(duì)象在構(gòu)造時(shí)要求有參數(shù),而它又有一個(gè)沒有參數(shù)的重載的構(gòu)造方法,你想想它肯定在沒有
    參數(shù)的構(gòu)造方法中調(diào)用了默認(rèn)參數(shù),你要做的就是把它們打印出來.有多少人是這樣做的?

        jdbc optional API的其它擴(kuò)展功能:
        javax.sql不僅僅是在性能上的提高,而且它還支持分布式事務(wù),在傳統(tǒng)的連結(jié)過程中,我們
    可以在一個(gè)連結(jié)過程中,setAutoCommit()為fasle,然后通過rollback()或commit()那回滾和提交事
    務(wù),這種在一個(gè)連結(jié)過程中的事務(wù)稱為本地事務(wù),但假如在一個(gè)事務(wù)中要對(duì)多個(gè)數(shù)據(jù)庫操作,或多過
    Servlet參與操作,那就必須使用分布式事務(wù).

        關(guān)于JDBC的事務(wù)我會(huì)放在下面來介紹,一個(gè)值得慶賀的功能出來了,就是事務(wù)保存點(diǎn)已經(jīng)
    JDBC3.0中實(shí)現(xiàn),以前,如果我們把事務(wù)原子A,B,C放在一個(gè)事務(wù)中,如果A,B執(zhí)行了,C失敗,我們只能
    把A,B都回滾了,但現(xiàn)在我們可以先把A,B保存為一個(gè)點(diǎn),然后以這個(gè)點(diǎn)為回滾或提交,這就象在用WORD
    編寫文章時(shí)我們可以在不同的時(shí)候保存一個(gè)副本,而不會(huì)要么一字沒有了,要么就是當(dāng)前編輯的狀態(tài).

        現(xiàn)在我們來優(yōu)化我們?cè)诨A(chǔ)知識(shí)中實(shí)現(xiàn)的Bean,今天在家,沒法上論壇,上次寫的連結(jié)部分
    叫什么名字忘記了,現(xiàn)在我們就叫它PooledDB吧.
        當(dāng)時(shí)我們已經(jīng)把那個(gè)Bean分為三個(gè)部分,把生成連結(jié)部分獨(dú)立出來了,而業(yè)務(wù)方法部份和擴(kuò)
    展部分根本不要?jiǎng)铀?這就是繼承的好處:)


    package com.inmsg.beans;

    import javax.naming.*;
    import javax.sql.*;

    public class PooledDB {
     
          Connection con = null;
          private String source = "";
          public PooledDB() throws Exception {//默認(rèn)構(gòu)造方法,如果構(gòu)造時(shí)不加參數(shù),連結(jié)jdbc/office
                source = "java:comp/env/jdbc/office";
                Context ct = new InitialContext();
                DataSource ds = (DataSource) ct.lookup(source);
              con = ds.getConnection();
        }
        
        //然后增加重載方法,用來連結(jié)其它的數(shù)據(jù)源    
        public PooledDB(String source) throws Exception {
                this.source = source;
                Context ct = new InitialContext();
                DataSource ds = (DataSource) ct.lookup(source);
              con = ds.getConnection();
        }
        //注意一定要先把source賦給成員變量this.source,因?yàn)橄旅孢€有一個(gè)makeConnection()
        //輔助方法,如果不把source賦給this.source,則makeConnection()調(diào)用默認(rèn)的source字符串

        private void makeConnection() throws Exception {
                Context ct = new InitialContext();
                DataSource ds = (DataSource) ct.lookup(source);
                con = ds.getConnection();
        }
        
        //現(xiàn)在我們把close()方法拿到父類來實(shí)現(xiàn),這是經(jīng)過綜合考慮的,它是一個(gè)業(yè)務(wù)方法,無論是什么
        //方式取得連結(jié),它本身不會(huì)修改,但為什么還封裝到父類中呢?因?yàn)檫@樣可以用一個(gè)獨(dú)立的父類來
        //做連結(jié)測試,如果我只想試一下數(shù)據(jù)庫能不能連結(jié),我就不必再引用子類,直接用這個(gè)父類就行了
        public void close() throws Exception{
            if(con != null && !con.isClosed()) con.close();
        }
    }

        一般來說,構(gòu)造方法盡量捕獲異常處理而不要拋出異常,但作為Bean的實(shí)現(xiàn),捕獲異常調(diào)用者不容易
    看到異常信息,所以拋給調(diào)用者處理,另外這個(gè)類又要在應(yīng)用程序中調(diào)用,又要考慮作為Bean調(diào)用,所以一定
    要有一個(gè)無參數(shù)的構(gòu)造方法,否則不能作為javaBean調(diào)用.把異常拋出給調(diào)用者的另一目的,我在設(shè)計(jì)時(shí)是這
    樣考慮的,就是強(qiáng)迫你一定在使用try{}catch(){}塊,這樣你就會(huì)想到再加一個(gè)finally{},再次提醒,一定要
    以下面的形式來調(diào)用你數(shù)據(jù)庫連結(jié)的Bean或封裝類:
        PooledDB pd = null;
        try{
            pd = new PooledDB();
            ....................
        }
        catch(Exception e){}
        finally{try{pd.close();}catch(Exception ex){}}
        
        如果要測試你的數(shù)據(jù)庫連結(jié)是否有泄漏,請(qǐng)你把DataSource中最大連結(jié)數(shù)設(shè)為1,只用一個(gè)連結(jié)的情
    況下,如果你的程序中哪一處沒有關(guān)閉連結(jié),則下面的程序就不能再訪問,然后從頭到尾測試你的程序吧,一旦
    發(fā)現(xiàn)不能訪問數(shù)據(jù)庫了,就查看剛才訪問的代碼,這樣所有程序測試后,就可以放心了,一般來說我是不用這么
    測試的,因?yàn)槲以趯憯?shù)據(jù)庫連結(jié)時(shí)是沒有生成對(duì)象就寫好close:

        PooledDB pd = null;
        try{}
        catch(Exception e){}
        finally{try{pd.close();}catch(Exception ex){}}
        然后原在try{}的花括號(hào)中回車加上pd = PooledDB();和業(yè)務(wù)代碼的 :)當(dāng)然,你們都比我聰明用不
    著這樣死套也不會(huì)忘記close()的.
        不要太高興,到目前為止你仍然還沒得到一個(gè)最好的解決方案,以下我們還會(huì)對(duì)這個(gè)數(shù)據(jù)庫連結(jié)的
    Bean(類)不斷優(yōu)化的..................................

        好了,javax.sql的連結(jié)先說到這兒吧,今天是周六,出去玩一會(huì)了(廣州街頭上沒有什么美女!)
    posted @ 2006-01-09 10:07 javaGrowing 閱讀(324) | 評(píng)論 (0)編輯 收藏

    僅列出標(biāo)題
    共19頁: First 上一頁 10 11 12 13 14 15 16 17 18 下一頁 Last 
    主站蜘蛛池模板: 免费国产美女爽到喷出水来视频| 亚洲伊人久久成综合人影院| 亚洲av日韩专区在线观看| 免费一级毛片免费播放| 成人无码a级毛片免费| 亚洲国产中文在线二区三区免| 成年性午夜免费视频网站不卡| 国产精品亚洲а∨无码播放麻豆 | 一级免费黄色毛片| 亚洲无线电影官网| 男女交性永久免费视频播放| 99久久成人国产精品免费| 亚洲免费视频网址| 在线观看国产区亚洲一区成人 | 亚洲福利精品电影在线观看| 一级毛片在线免费看| 亚洲AV色无码乱码在线观看| 亚洲VA中文字幕无码一二三区 | 黄色永久免费网站| igao激情在线视频免费| 亚洲国产美女视频| 中文字幕久久亚洲一区 | 免费乱码中文字幕网站| 97在线视频免费公开观看| 国产成人精品亚洲| 久久亚洲AV成人无码| 亚洲精品人成无码中文毛片| 免费人成网站在线观看10分钟| 国产特黄一级一片免费| 亚洲精品无码中文久久字幕| 亚洲av激情无码专区在线播放| 国产午夜鲁丝片AV无码免费| 亚洲美女免费视频| 三年片免费高清版| 国产精品亚洲色图| 久久久久se色偷偷亚洲精品av| 亚洲AV无一区二区三区久久| 亚洲精品无码久久久久AV麻豆| 成年女人18级毛片毛片免费| 91精品免费不卡在线观看| 精品乱子伦一区二区三区高清免费播放|