已閱讀5頁,還剩85頁未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
java網(wǎng)絡(luò)編程精解,作者:孫衛(wèi)琴參考書籍:技術(shù)支持網(wǎng)址:,第12章通過jdbcapi訪問數(shù)據(jù)庫,參考java網(wǎng)絡(luò)編程精解的第12章,12.1jdbc的實(shí)現(xiàn)原理12.2安裝和配置mysql數(shù)據(jù)庫12.3jdbcapi簡介12.4jdbcapi的基本用法12.5可滾動以及可更新的結(jié)果集12.6行集12.7調(diào)用存儲過程12.8處理blob和clob類型數(shù)據(jù)12.9控制事務(wù)12.10數(shù)據(jù)庫連接池,第12章通過jdbcapi訪問數(shù)據(jù)庫,jdk提供了jdbcapi。jdbc是javadatabaseconnectivity的縮寫。jdbc的實(shí)現(xiàn)封裝了與各種數(shù)據(jù)庫服務(wù)器通信的細(xì)節(jié)。java程序通過jdbcapi來訪問數(shù)據(jù)庫,有以下優(yōu)點(diǎn):(1)簡化訪問數(shù)據(jù)庫的程序代碼,無需涉及與數(shù)據(jù)庫服務(wù)器通信的細(xì)節(jié)。(2)不依賴于任何數(shù)據(jù)庫平臺。同一個(gè)java程序可以訪問多種數(shù)據(jù)庫服務(wù)器。,第12章通過jdbcapi訪問數(shù)據(jù)庫,12.1jdbc的實(shí)現(xiàn)原理,jdbc的實(shí)現(xiàn)包括三部分:jdbc驅(qū)動管理器:java.sql.drivermanger類,由sun公司實(shí)現(xiàn),負(fù)責(zé)注冊特定jdbc驅(qū)動器,以及根據(jù)特定驅(qū)動器建立與數(shù)據(jù)庫的連接。jdbc驅(qū)動器api:由sun公司制定,其中最主要的接口是java.sql.driver接口。jdbc驅(qū)動器:由數(shù)據(jù)庫供應(yīng)商或者其他第三方工具提供商創(chuàng)建,也稱為jdbc驅(qū)動程序。jdbc驅(qū)動器實(shí)現(xiàn)了jdbc驅(qū)動器api,負(fù)責(zé)與特定的數(shù)據(jù)庫連接,以及處理通信細(xì)節(jié)。jdbc驅(qū)動器可以注冊到j(luò)dbc驅(qū)動管理器中。,12.1jdbc的實(shí)現(xiàn)原理,12.1jdbc的實(shí)現(xiàn)原理,sun公司制定了兩套api:jdbcapi:java應(yīng)用程序通過它來訪問各種數(shù)據(jù)庫。jdbc驅(qū)動器api:當(dāng)數(shù)據(jù)庫供應(yīng)商或者其他第三方工具提供商為特定數(shù)據(jù)庫創(chuàng)建jdbc驅(qū)動器時(shí),該驅(qū)動器必須實(shí)現(xiàn)jdbc驅(qū)動器api。,12.1jdbc的實(shí)現(xiàn)原理,jdbc驅(qū)動器可分為以下四類:第1類驅(qū)動器:jdbc-odbc驅(qū)動器。第2類驅(qū)動器:由部分java程序代碼和部分本地代碼組成。用于與數(shù)據(jù)庫的客戶端api通信。第3類驅(qū)動器:完全由java語言編寫的類庫。它用一種與具體數(shù)據(jù)庫服務(wù)器無關(guān)的協(xié)議將請求發(fā)送給服務(wù)器的特定組件,再由該組件按照特定數(shù)據(jù)庫協(xié)議對請求進(jìn)行翻譯,并把翻譯后的內(nèi)容發(fā)送給數(shù)據(jù)庫服務(wù)器。第4類驅(qū)動器:完全由java語言編寫的類庫。它直接按照特定數(shù)據(jù)庫的協(xié)議,把請求發(fā)送給數(shù)據(jù)庫服務(wù)器。,12.2安裝和配置mysql數(shù)據(jù)庫,假定mysql安裝后的根目錄為,在/bin目錄下提供了mysql.exe,它是mysql的客戶程序,它支持在命令行中輸入sql語句,圖12-4顯示了mysql客戶程序的界面。,12.2安裝和配置mysql數(shù)據(jù)庫,本節(jié)課訪問數(shù)據(jù)庫的例子都以storedb數(shù)據(jù)庫為例。在storedb數(shù)據(jù)庫中有三張表:customers表:保存了客戶信息。本章多數(shù)例子都訪問這張表。orders表:保存了客戶發(fā)出的訂單信息。orders表的order_number字段表示訂單編號,price字段表示訂單價(jià)格。orders表的customer_id外鍵參照customers表的id主鍵,參見圖12-5。accounts表:保存了銀行賬戶的信息,balance字段表示賬戶的余額。,12.2安裝和配置mysql數(shù)據(jù)庫,例程12-1的schema.sql是一個(gè)sql腳本文件,它包含了創(chuàng)建數(shù)據(jù)庫storedb以及三張表的所有sql語句。例程12-1schema.sqldropdatabaseifexistsstoredb;createdatabasestoredb;usestoredb;createtablecustomers(idbigintnotnullauto_incrementprimarykey,namevarchar(16)notnull,ageint,addressvarchar(255);,12.2安裝和配置mysql數(shù)據(jù)庫,createtableorders(idbigintnotnullauto_incrementprimarykey,order_numbervarchar(16)notnull,pricefloat,customer_idbigint,foreignkey(customer_id)referencescustomers(id);createtableaccounts(idbigintnotnull,namevarchar(15),balancedecimal(10,2),primarykey(id)type=innodb;insertintocustomers(id,name,age,address)values(1,小張,23,北京);insertintoorders(id,order_number,price,customer_id)values(1,小張_001,100.12,1);select*fromcustomers;select*fromorders;,12.3jdbcapi簡介,jdbcapi主要位于java.sql包中,關(guān)鍵的接口與類包括:driver接口和drivermanager類:前者表示驅(qū)動器,后者表示驅(qū)動管理器。connection接口:表示數(shù)據(jù)庫連接。statement接口:負(fù)責(zé)執(zhí)行sql語句。preparedstatement接口:負(fù)責(zé)執(zhí)行預(yù)準(zhǔn)備的sql語句。callablestatement接口:負(fù)責(zé)執(zhí)行sql存儲過程。resultset接口:表示sql查詢語句返回的結(jié)果集。,12.3jdbcapi簡介,圖12-6為java.sql包中主要的接口與類的類框圖。,12.3jdbcapi簡介,1.driver接口和drivermanager類所有jdbc驅(qū)動器都必須實(shí)現(xiàn)driver接口,jdbc驅(qū)動器由數(shù)據(jù)庫廠商或第三方提供。drivermanager類主要包括以下方法:registerdriver(driverdriver):在drivermanger中注冊jdbc驅(qū)動器。getconnection(stringurl,stringuser,stringpwd):建立和數(shù)據(jù)庫的連接,并返回表示數(shù)據(jù)庫連接的connection對象。setlogintimeout(intseconds):設(shè)定等待建立數(shù)據(jù)庫連接的超時(shí)時(shí)間。setlogwriter(printwriterout):設(shè)定輸出jdbc日志的printwriter對象。,12.3jdbcapi簡介,2.connection接口connection接口主要包括以下方法:getmetadata():返回表示數(shù)據(jù)庫的元數(shù)據(jù)的databasemetadata對象。元數(shù)據(jù)包含了描述數(shù)據(jù)庫的相關(guān)信息,本章12.4.10節(jié)(元數(shù)據(jù))進(jìn)一步介紹了元數(shù)據(jù)的作用。createstatement():創(chuàng)建并返回statement對象。preparestatement(stringsql):創(chuàng)建并返回preparedstatement對象。,12.3jdbcapi簡介,3.statement接口statement接口提供了三個(gè)執(zhí)行sql語句的方法:execute(stringsql):執(zhí)行各種sql語句。executeupdate(stringsql):執(zhí)行sql的insert、update和delete語句。該方法返回一個(gè)int類型的值,表示數(shù)據(jù)庫中受該sql語句影響的記錄的數(shù)目。executequery(stringsql):執(zhí)行sql的select語句。該方法返回一個(gè)表示查詢結(jié)果的resultset對象。,12.3jdbcapi簡介,4.preparedstatement接口preparedstatement的使用步驟如下:(1)通過connection的preparestatement()方法生成preparedstatement對象。以下sql語句中name的值和age的值都用“?”代替,它們表示兩個(gè)可被替換的參數(shù):stringsql=selectid,name,age,addressfromcustomerswherename=?andage=?;preparedstatementstmt=con.preparestatement(sql);/預(yù)準(zhǔn)備sql語句(2)調(diào)用preparedstatement的setxxx方法,給參數(shù)賦值:stmt.setstring(1,tom);/替換sql語句中的第一個(gè)“?”stmt.setint(2,20);/替換sql語句中的第二個(gè)“?”(3)執(zhí)行sql語句:resultsetrs=stmt.executequery();,12.3jdbcapi簡介,5.resultset接口resultset接口表示select查詢語句得到的結(jié)果集,結(jié)果集中的記錄的行號從1開始。調(diào)用resultset對象的next()方法,可以使游標(biāo)定位到結(jié)果集中的下一條記錄。調(diào)用resultset對象的getxxx()方法,可以獲得一條記錄中某個(gè)字段的值。,12.3jdbcapi簡介,5.resultset接口對于以下的select查詢語句,結(jié)果集存放在一個(gè)resultset對象中:stringsql=selectid,name,age,addressfromcustomerswhereage20;resultsetrs=stmt.executequery(sql);如果要訪問name字段,可以采用以下兩種方式:rs.getstring(2);/指定字段的索引位置或者rs.getstring(name);/指定字段的名字,12.4jdbcapi的基本用法,在java程序中,通過jdbcapi訪問數(shù)據(jù)庫包括以下步驟。(1)獲得要訪問的數(shù)據(jù)庫的驅(qū)動器的類庫,把它放到classpath中。(2)在程序中加載并注冊jdbc驅(qū)動器,其中jdbc-odbc驅(qū)動器是在jdk中自帶的,默認(rèn)已經(jīng)注冊,所以不需要再注冊。以下給出了加載并注冊mysql驅(qū)動器的代碼:/注冊mysqldriverjava.sql.drivermanager.registerdriver(newcom.mysql.jdbc.driver();,12.4jdbcapi的基本用法,(3)建立與數(shù)據(jù)庫的連接:connectioncon=java.sql.drivermanager.getconnection(dburl,user,password);(4)創(chuàng)建statement對象,準(zhǔn)備執(zhí)行sql語句:statementstmt=con.createstatement();編寫jdc程序的步驟(5)執(zhí)行sql語句:stringsql=selectid,name,age,addressfromcustomerswhereage20;resultsetrs=stmt.executequery(sql);,12.4jdbcapi的基本用法,(6)遍歷resultset對象中的記錄:/輸出查詢結(jié)果while(rs.next()longid=rs.getlong(1);stringname=rs.getstring(2);intage=rs.getint(3);stringaddress=rs.getstring(4);/打印數(shù)據(jù)system.out.println(id=+id+,name=+name+,age=+age+,address=+address);,12.4jdbcapi的基本用法,(7)依次關(guān)閉resultset、statement和connection對象:rs.close();stmt.close();con.close();,12.4jdbcapi的基本用法,resultset、statement和connection都有close()方法,它們的作用如下:resultset的close()方法:釋放結(jié)果集占用的資源。當(dāng)resultset對象被關(guān)閉后,就不允許程序再訪問它曾經(jīng)包含的查詢結(jié)果,不允許調(diào)用它的next()和getxxx()等方法。statement的close()方法:釋放statement對象占用的資源。關(guān)閉statement對象時(shí),與它關(guān)聯(lián)的resultset對象也被自動關(guān)閉。當(dāng)statement對象被關(guān)閉后,就不允許通過它執(zhí)行任何sql語句。connection的close()方法:釋放connection對象占用的資源,斷開數(shù)據(jù)庫連接。關(guān)閉connection對象時(shí),與它關(guān)聯(lián)的所有statement對象也被自動關(guān)閉。當(dāng)connection對象被關(guān)閉后,就不允許通過它創(chuàng)建statement對象。,12.5可滾動以及可更新的結(jié)果集,為了獲得可滾動或者可更新的resultset對象,需要通過connection接口的以下方法構(gòu)造statement或者preparedstatement對象:createstatement(inttype,intconcurrency)/創(chuàng)建statement對象preparestatement(stringsql,inttype,intconcurrency)/創(chuàng)建preparedstatement,12.5可滾動以及可更新的結(jié)果集,以上type和concurrency參數(shù)決定了由statement或preparedstatement對象創(chuàng)建的resultset對象的特性。type參數(shù)有以下可選值:resultset.type_forward_only:游標(biāo)只能從上往下移動,即結(jié)果集不能滾動。這是默認(rèn)值。resultset.type_scroll_insensitive:游標(biāo)可以上下移動,即結(jié)果集可以滾動。當(dāng)程序?qū)Y(jié)果集的內(nèi)容作了修改,游標(biāo)對此不敏感。resultset.type_scroll_sensitive:游標(biāo)可以上下移動,即結(jié)果集可以滾動。當(dāng)程序?qū)Y(jié)果集的內(nèi)容作了修改,游標(biāo)對此敏感。比如當(dāng)程序刪除了結(jié)果集中的一條記錄時(shí),游標(biāo)位置會隨之發(fā)生變化。,12.5可滾動以及可更新的結(jié)果集,concurrency參數(shù)有以下可選值:concur_read_only:結(jié)果集不能被更新。concur_updatable:結(jié)果集可以被更新。例如,按照以下方式創(chuàng)建的結(jié)果集可以滾動,但不能被更新。statementstmt=connection.createstatement(resultset.type_scroll_insensitive,resultset.concur_read_only);resultsetrs=stmt.executequery(selectid,namefromcustomers);,12.5可滾動以及可更新的結(jié)果集,resultset接口提供了一系列用于移動游標(biāo)的方法:first():使游標(biāo)移動到第一條記錄。last():使游標(biāo)移動到最后一條記錄。beforefirst():使游標(biāo)移動到結(jié)果集的開頭。afterlast():使游標(biāo)移動到結(jié)果集的末尾。previous():使游標(biāo)從當(dāng)前位置向上(或者說向前)移動一行。next():使游標(biāo)從當(dāng)前位置向下(或者說向后)移動一行。relative(intn):使游標(biāo)從當(dāng)前位置移動n行。如果n0,就向下移動,否則就向上移動。當(dāng)n為1,等價(jià)于調(diào)用next()方法;當(dāng)n為-1,等價(jià)于調(diào)用previous()方法。absolute(intn):使游標(biāo)移動到第n行。參數(shù)n指定游標(biāo)的絕對位置。,12.5可滾動以及可更新的結(jié)果集,resultset接口的以下方法判斷游標(biāo)是否在特定位置:isfirst():判斷游標(biāo)是否在第一行。islast():判斷游標(biāo)是否在最后一行。isbeforefirst():判斷游標(biāo)是否在結(jié)果集的開頭。isafterlast():判斷游標(biāo)是否在結(jié)果集的末尾。,12.5可滾動以及可更新的結(jié)果集,插入記錄:rs.movetoinsertrow();rs.updatestring(name,小王);rs.updateint(age,25);resultset.updatestring(address,上海);resultset.insertrow();/插入一條記錄resultset.movetocurrentrow();/把游標(biāo)移動到插入前的位置,12.5可滾動以及可更新的結(jié)果集,更新記錄:rs.updatestring(name,小王);rs.updateint(age,29);resultset.updatestring(address,安徽);resultset.updaterow();/更新記錄刪除記錄:resultset.deleterow();/刪除一條記錄,12.6行集,可滾動的resultset對象盡管便于用戶操縱結(jié)果集,但是有一個(gè)很大的缺陷,那就是在結(jié)果集打開期間,必須始終與數(shù)據(jù)庫保持連接。為了更有效的使用數(shù)據(jù)庫連接,jdbcapi提供了另一個(gè)用于操縱查詢結(jié)果的行集接口:javax.sql.rowset。rowset接口繼承了resultset接口,因此rowset接口也能操縱查詢結(jié)果。,12.6行集,rowset具有以下特性:它的cachedrowset子接口無需始終與數(shù)據(jù)庫保持連接。rowset對象的數(shù)據(jù)結(jié)構(gòu)沒有resultset對象那么龐大,并且rowset對象不依賴于數(shù)據(jù)庫連接,因此在分層的軟件應(yīng)用中,可以方便的把rowset對象移動到其他層。rowset對象表示的行集總是可以滾動的。,12.6行集,如圖12-11所示,在應(yīng)用服務(wù)器層創(chuàng)建了一個(gè)rowset對象,它包含了某種查詢結(jié)果。該rowset對象被傳到客戶層,在圖形用戶界面上展示給用戶。,12.6行集,rowset接口有若干子接口,它們都位于javax.sql.rowset包中:cachedrowset接口:被緩存的行集,查詢結(jié)果被保存到內(nèi)存中,允許在斷開數(shù)據(jù)庫連接的情況下訪問內(nèi)存中的查詢結(jié)果。webrowset接口:被緩存的行集,并且行集中的查詢結(jié)果可以保存到一個(gè)xml文件中。filteredrowset和joinrowset接口:被緩存的行集,并且支持對行集的輕量級操作。其中filteredrowset能夠根據(jù)設(shè)置條件得到查詢結(jié)果的子集;joinrowset能夠?qū)讉€(gè)rowset對象用sqljoin語句進(jìn)行連接。jdbcrowset接口:resultset接口的瘦包裝器,jdbcrowset接口從rowset接口中繼承了get和set方法,從而將一個(gè)結(jié)果集轉(zhuǎn)換為一個(gè)javabean。,12.6行集,sun公司希望數(shù)據(jù)庫供應(yīng)商為rowset接口的子接口提供高性能的實(shí)現(xiàn)。此外,sun公司為這些接口提供了參考實(shí)現(xiàn),它們都位于com.sun.rowset包中,實(shí)現(xiàn)類都以impl結(jié)尾,例如cachedrowset接口的參考實(shí)現(xiàn)類為com.sun.rowset.cachedrowsetimpl。有了這些參考實(shí)現(xiàn),即使數(shù)據(jù)庫供應(yīng)商不支持rowset接口,也能在程序中使用它們。,12.6行集,cachedrowset的使用步驟如下。(1)創(chuàng)建一個(gè)cachedrowset對象。以下代碼創(chuàng)建的cachedrowset對象是sun公司提供的參考實(shí)現(xiàn)類cachedrowsetimpl的實(shí)例:cachedrowsetrowset=newcom.sun.rowset.cachedrowsetimpl()(2)向cachedrowset對象中填充查詢結(jié)果??梢圆捎脙煞N方式:一種方式是把resultset對象中的查詢結(jié)果填充到cachedrowset對象中:resultsetrs=stmt.executequery(sql);rowset.populate(rs);con.close();/關(guān)閉數(shù)據(jù)庫連接,12.6行集,(3)滾動行集的方式與滾動結(jié)果集的方式相同。以下代碼自下而上遍歷行集中的內(nèi)容:rowset.afterlast();/把游標(biāo)移動到行集的末尾while(rowset.previous()longid=rowset.getlong(1);stringname=rowset.getstring(2);intage=rowset.getint(3);stringaddress=rowset.getstring(4);,12.6行集,(4)對行集的更新僅僅改變了行集中的數(shù)據(jù)(實(shí)質(zhì)上是對內(nèi)存中數(shù)據(jù)的更新),為了能反映到數(shù)據(jù)庫中,必須重新建立數(shù)據(jù)庫連接,再更新數(shù)據(jù)庫。cachedrowset的acceptchanges()方法負(fù)責(zé)按照行集中數(shù)據(jù)的變化去更新數(shù)據(jù)庫。acceptchanges()方法有兩種重載形式:publicvoidacceptchanges()throwssyncproviderexceptionpublicvoidacceptchanges(connectioncon)throwssyncproviderexception如果已經(jīng)通過seturl()、setusername()和setpassword()方法設(shè)置了連接數(shù)據(jù)庫的屬性,就可以調(diào)用不帶參數(shù)的acceptchanges()方法,該方法會自動建立數(shù)據(jù)庫連接,然后在更新完數(shù)據(jù)庫后再關(guān)閉連接;否則必須調(diào)用帶connection類型參數(shù)的acceptchanges(connectioncon)方法,該方法直接用參數(shù)提供的連接去訪問數(shù)據(jù)庫,在更新完數(shù)據(jù)庫后不會關(guān)閉連接,程序必須顯式的關(guān)閉連接:rowset.accecptchanges(con);con.close();/顯式的關(guān)閉連接,12.6行集,以下程序代碼演示如何通過行集插入、更新和刪除記錄。/插入記錄rowset.movetoinsertrow();rowset.updatestring(name,小王);rowset.updateint(age,25);rowset.updatestring(address,上海);rowset.insertrow();/插入一條記錄rowset.movetocurrentrow();/把游標(biāo)移動到插入前的位置rowset.acceptchanges(con);con.close();/更新記錄rowset.updatestring(name,小王);rowset.updateint(age,29);rowset.updatestring(address,安徽);rowset.updaterow();/更新當(dāng)前記錄rowset.acceptchanges(con);con.close();/刪除記錄resultset.deleterow();/刪除當(dāng)前記錄rowset.acceptchanges(con);con.close();,12.7調(diào)用存儲過程,java.sql.callablestatement接口用來執(zhí)行數(shù)據(jù)庫中的存儲過程。connection的preparecall()方法創(chuàng)建一個(gè)callablestatement對象。假定一個(gè)存儲過程有兩個(gè)參數(shù),創(chuàng)建callablestatement對象的代碼如下:callablestatementcstmt=con.preparecall(call存儲過程的名字(?,?);以上兩個(gè)問號分別代表存儲過程的兩個(gè)參數(shù)。,12.7調(diào)用存儲過程,假設(shè)mysql數(shù)據(jù)庫中有一個(gè)名為demosp的存儲過程,它的定義如下:createproceduredemosp(ininputparamvarchar(255),inoutinoutparamint)begindeclarezint;setz=inoutparam+1;setinoutparam=z;selectconcat(hello,inputparam);end,12.7調(diào)用存儲過程,以下例程12-14的proceduretester類演示如何調(diào)用該存儲過程。例程12-14proceduretester.javaimportjava.sql.*;publicclassproceduretesterpublicstaticvoidmain(stringargs)throwsexceptionconnectioncon=newconnectionprovider().getconnection();/創(chuàng)建一個(gè)調(diào)用demosp存儲過程的callablestatement對象。callablestatementcstmt=con.preparecall(calldemosp(?,?);/設(shè)置第一個(gè)參數(shù)的值cstmt.setstring(1,tom);/按索引位置指定參數(shù)/cstmt.setstring(inputparam,tom);/按名字指定參數(shù)/注冊第二個(gè)參數(shù)的類型cstmt.registeroutparameter(2,types.integer);/按索引位置指定參數(shù)/cstmt.registeroutparameter(inoutparam,types.integer);/按名字指定參數(shù),12.7調(diào)用存儲過程,/設(shè)置第二個(gè)參數(shù)的值cstmt.setint(2,1);/按索引位置指定參數(shù)/cstmt.setint(inoutparam,1);/按名字指定參數(shù)booleanhadresults=cstmt.execute();/執(zhí)行存儲過程/訪問結(jié)果集if(hadresults)resultsetrs=cstmt.getresultset();/sqlexecutor類參見12.4.4節(jié)的例程12-8sqlexecutor.showresultset(rs);/獲得第二個(gè)參數(shù)的輸出值intoutputvalue=cstmt.getint(2);/按索引位置指定參數(shù)/intoutputvalue=cstmt.getint(inoutparam);/按名字指定參數(shù)con.close();,12.8處理blob和clob類型數(shù)據(jù),在數(shù)據(jù)庫中有兩種特殊的sql數(shù)據(jù)類型:blob(binarylargeobject):存放大容量的二進(jìn)制數(shù)據(jù)。clob(characterobject):存放大容量的由字符組成的文本數(shù)據(jù)。,12.8處理blob和clob類型數(shù)據(jù),假設(shè)數(shù)據(jù)庫的一張表中有一個(gè)名為file的字段,該字段為blob類型,這張表的某條記錄的file字段存放了100m的數(shù)據(jù)。如何通過jdbcapi來讀取這個(gè)字段呢?很簡單,只要調(diào)用resultset對象的getblob()方法就可以了:statementstmt=con.createstatement();resultsetrs=stmt.executequery(selectfilefromablobwhereid=1);rs.next();blobblob=rs.getblob(file);resultset對象的getblob()方法返回一個(gè)blob對象。,12.8處理blob和clob類型數(shù)據(jù),為了獲取數(shù)據(jù)庫中的blob數(shù)據(jù),可以調(diào)用blob對象的getbinarystream()方法獲得一個(gè)輸入流,然后從這個(gè)輸入流中讀取blob數(shù)據(jù)。以下程序代碼把數(shù)據(jù)庫中的blob數(shù)據(jù)拷貝到一個(gè)文件中:/把數(shù)據(jù)庫中的blob數(shù)據(jù)拷貝到test_bak.gif文件中inputstreamin=blob.getbinarystream();fileoutputstreamfout=newfileoutputstream(test_bak.gif);intb=-1;while(b=in.read()!=-1)fout.write(b);fout.close();in.close();,12.8處理blob和clob類型數(shù)據(jù),12.8處理blob和clob類型數(shù)據(jù),jdbcapi中處理clob數(shù)據(jù)的方法包括:resultset接口的getclob()方法:從結(jié)果集中獲得clob對象。clob接口的getcharacterstream()方法:返回一個(gè)reader對象,用于讀取clob數(shù)據(jù)中的字符。preparedstatement接口的setcharacterstream()方法:向數(shù)據(jù)庫中寫入clob數(shù)據(jù)。它的完整的定義如下:publicvoidsetcharacterstream(intparameterindex,readerreader,intlength)throwsexception,12.9控制事務(wù),事務(wù)是指一組相互依賴的操作行為。只有事務(wù)中的所有操作成功,才意味著整個(gè)事務(wù)成功,只要有一個(gè)操作失敗,就意味著整個(gè)事務(wù)失敗。在數(shù)據(jù)庫系統(tǒng)中,事務(wù)實(shí)際上就是一組sql語句,這些sql語句通常會涉及更新數(shù)據(jù)庫中的數(shù)據(jù)的操作。,12.9.1事務(wù)的概念,tom到銀行辦理轉(zhuǎn)賬事務(wù),把100元錢轉(zhuǎn)到j(luò)ack的賬號上,這個(gè)事務(wù)包含以下操作行為:(1)從tom的賬戶上減去100元。(2)往jack的賬戶上增加100元。顯然,以上兩個(gè)操作必須作為一個(gè)不可分割的工作單元。,12.9.1事務(wù)的概念,數(shù)據(jù)庫事務(wù)是對現(xiàn)實(shí)生活中事務(wù)的模擬,它由一組在業(yè)務(wù)邏輯上相互依賴的sql語句組成。假定accounts表用于存放賬戶信息,它的數(shù)據(jù)如表12-2所示。以上銀行轉(zhuǎn)賬事務(wù)對應(yīng)于以下sql語句:updateaccountssetbalance=900whereid=1;updateaccountssetbalance=1100whereid=2;,12.9.1事務(wù)的概念,12.9.2聲明事務(wù)邊界的概念,數(shù)據(jù)庫系統(tǒng)的客戶程序只要向數(shù)據(jù)庫系統(tǒng)聲明了一個(gè)事務(wù),數(shù)據(jù)庫系統(tǒng)就會自動保證事務(wù)的acid特性。聲明事務(wù)包含以下內(nèi)容:事務(wù)的開始邊界。事務(wù)的正常結(jié)束邊界(commit):提交事務(wù),永久保存被事務(wù)更新后的數(shù)據(jù)庫狀態(tài)。事務(wù)的異常結(jié)束邊界(rollback):撤銷事務(wù),或者說回滾事務(wù),使數(shù)據(jù)庫退回到執(zhí)行事務(wù)前的初始狀態(tài)。,12.9.2聲明事務(wù)邊界的概念,12.9.2聲明事務(wù)邊界的概念,數(shù)據(jù)庫系統(tǒng)支持兩種事務(wù)模式:自動提交模式:每個(gè)sql語句都是一個(gè)獨(dú)立的事務(wù),當(dāng)數(shù)據(jù)庫系統(tǒng)執(zhí)行完一個(gè)sql語句后,會自動提交事務(wù)。手工提交模式:必須由數(shù)據(jù)庫的客戶程序顯式指定事務(wù)開始邊界和結(jié)束邊界。,12.9.2聲明事務(wù)邊界的概念,在圖12-16中,mysql.exe是mysql軟件自帶的dos命令行客戶程序。而java應(yīng)用程序則通過jdbcapi訪問數(shù)據(jù)庫。,12.9.3在mysql.exe程序中聲明事務(wù),如果要察看當(dāng)前的事務(wù)模式,可使用如下sql命令:mysqlselectautocommit如果要把當(dāng)前的事務(wù)模式改為手工提交模式,可使用如下sql命令:mysqlsetautocommit=0;,12.9.3在mysql.exe程序中聲明事務(wù),在手工提交模式下,必須顯式指定事務(wù)開始邊界和結(jié)束邊界:事務(wù)的開始邊界:begin提交事務(wù):commit撤銷事務(wù):rollback例如:mysqlbegin;mysqlselect*fromaccounts;mysqlcommit;,12.9.3在mysql.exe程序中聲明事務(wù),再例如:mysqlbegin;mysqldeletefromaccounts;mysqlcommit;mysqlbegin;mysqlinsertintoaccountsvalues(1,tom,1000);mysqlinsertintoaccountsvalues(2,jack,1000);mysqlrollback;mysqlbegin;mysqlselect*fromaccounts;mysqlcommit;以上sql語句共包含三個(gè)事務(wù):第一個(gè)事務(wù)刪除accounts表中所有的記錄,然后提交該事務(wù);第二個(gè)事務(wù)最后以撤銷事務(wù)結(jié)束,因此它向accounts表插入的兩條記錄不會被永久保存到數(shù)據(jù)庫中;第三個(gè)事務(wù)的select語句的查詢結(jié)果為空。,12.9.4通過jdbcapi聲明事務(wù)邊界,connection接口提供了以下用于控制事務(wù)的方法:setautocommit(booleanautocommit):設(shè)置是否自動提交事務(wù)commit():提交事務(wù)rollback():撤銷事務(wù)對于新建的connection對象,默認(rèn)情況下采用自動提交事務(wù)模式??梢酝ㄟ^setautocommit(false)方法來設(shè)置手工提交事務(wù)模式。,12.9.4通過jdbcapi聲明事務(wù)邊界,處理事務(wù)的通用流程:trycon=drivermanager.getconnection(dburl,dbuser,dbpwd);/設(shè)置手工提交事務(wù)模式con.setautocommit(false);stmt=con.createstatement();/數(shù)據(jù)庫更新操作1stmt.executeupdate(updateaccountssetbalance=900whereid=1);/數(shù)據(jù)庫更新操作2stmt.executeupdate(updateaccountssetbalance=1100whereid=2);mit();/提交事務(wù),12.9.4通過jdbcapi聲明事務(wù)邊界,catch(exceptione)trycon.rollback();/操作不成功則撤銷事務(wù)catch(exceptionex)/處理異常/處理異常finallytrystmt.close();con.close();catch(exceptionex)/處理異常,12.9.5保存點(diǎn),如果只希望撤銷事務(wù)中的部分操作,那么可以在事務(wù)中加入保存點(diǎn)。如圖12-17所示,某個(gè)事務(wù)包括5個(gè)操作,在操作1后面設(shè)置了保存點(diǎn)a,在操作3后面設(shè)置了保存點(diǎn)b。如果在執(zhí)行完操作4后,把事務(wù)回滾到保存點(diǎn)b,那么會撤銷操作4對數(shù)據(jù)庫所作的更新。如果在執(zhí)行完操作5后,把事務(wù)回滾到保存點(diǎn)a,那么會撤銷操作5、操作4、操作3和操作2對數(shù)據(jù)庫所作的更新。,12.9.5保存點(diǎn),connection接口的setsavepoint()方法用于在事務(wù)中設(shè)置保存點(diǎn),它有兩種重載形式:publicsavepointsetsavepoint()throwssqlexceptionpublicsavepointsetsavepoint(stringname)throwssqlexception以上第一個(gè)不帶參數(shù)的setsavepoint()方法設(shè)置匿名的保存點(diǎn),第二個(gè)setsavepoint(stringname)方法的name參數(shù)表示保存點(diǎn)的名字。這兩個(gè)setsavepoint()方法都會返回一個(gè)表示保存點(diǎn)的savepoint對象。connection接口的releasesavepoint(savepointpoint)方法取消已經(jīng)設(shè)置的保存點(diǎn)。connection接口的rollback(savepointpoint)方法使事務(wù)回滾到參數(shù)指定的保存點(diǎn)。,12.9.6批量更新,從jdbc2.0開始,允許用批量更新的方式來執(zhí)行大批量操作,它能提高操縱數(shù)據(jù)庫的效率。在statement接口中提供了支持批量更新的兩個(gè)方法:addbatch(stringsql):加入一條sql語句。executebatch():執(zhí)行批量更新。前面已經(jīng)講過,statement接口的executeupdate(stringsql)方法返回一個(gè)整數(shù),表示數(shù)據(jù)庫中受sql語句影響的記錄數(shù)。而executebatch()方法則返回一個(gè)int數(shù)組,數(shù)組中的每個(gè)元素分別表示受每條sql語句影響的記錄數(shù)。,12.9.7設(shè)置事務(wù)隔離級別,在多用戶環(huán)境中,如果多個(gè)事務(wù)同時(shí)操縱數(shù)據(jù)庫中的相同數(shù)據(jù),就會導(dǎo)致各種并發(fā)問題。為了避免這些并發(fā)問題,數(shù)據(jù)庫提供了四種事務(wù)隔離級別:serializable:串行化repeatableread:可重復(fù)讀readcommited:讀已提交數(shù)據(jù)readuncommited:讀未提交數(shù)據(jù)數(shù)據(jù)庫系統(tǒng)采用不同的鎖類型來實(shí)現(xiàn)以上四種隔離級別,具體的實(shí)現(xiàn)過程對用戶是透明的。用戶應(yīng)該關(guān)心的是如何選擇合適的隔離級別。,12.9.7設(shè)置事務(wù)隔離級別,在四種隔離級別中,serializable的隔離級別最高,readuncommited的隔離級別最差。,12.9.7設(shè)置事務(wù)隔離級別,隔離級別越高,越能保證數(shù)據(jù)庫中數(shù)據(jù)的完整性和一致性,但是對并發(fā)性能的影響也越大,圖12-18顯示了隔離級別與并發(fā)性能的關(guān)系。對于多數(shù)應(yīng)用程序,可以優(yōu)先考慮把數(shù)據(jù)庫系統(tǒng)的隔離級別設(shè)為readcommitted,它能夠避免臟讀,而且具有較好的并發(fā)性能。盡管它會導(dǎo)致不可重復(fù)讀、虛讀和第二類丟失更新這些并發(fā)問題,在可能出現(xiàn)這類問題的個(gè)別場合,可以由應(yīng)用程序采用悲觀鎖或樂觀鎖機(jī)制來控制。,12.9.7設(shè)置事務(wù)隔離級別,connection接口的settransactionisolation(intlevel)用來設(shè)置數(shù)據(jù)庫系統(tǒng)使用的隔離級別,這種設(shè)置只對當(dāng)前的連接有效。參數(shù)level有以下可選值:connection.transaction_read_uncommittedconnection.transaction_read_committedconnection.transaction_repeatable_readconnection.transaction_serializable,12.10數(shù)據(jù)庫連接池,建立一個(gè)數(shù)據(jù)庫連接需要消耗大量系統(tǒng)資源,頻繁的創(chuàng)建數(shù)據(jù)庫連接會大大削弱應(yīng)用的訪問數(shù)據(jù)庫的性能。為了解決這一問題,數(shù)據(jù)庫連接池應(yīng)運(yùn)而生。數(shù)據(jù)庫連接池的基本實(shí)現(xiàn)原理是:事先建立一定數(shù)量的數(shù)據(jù)庫連接,這些連接存放在連接池中,當(dāng)java應(yīng)用執(zhí)行一個(gè)數(shù)據(jù)庫事務(wù)時(shí),只需從連接池中取出空閑的數(shù)據(jù)庫連接;當(dāng)java應(yīng)用執(zhí)行完事務(wù),再將數(shù)據(jù)庫連接放回連接池。,12.10數(shù)據(jù)庫連接池,12.10數(shù)據(jù)庫連接池,12.10數(shù)據(jù)庫連接池,各種連接池產(chǎn)品會使用不同的實(shí)現(xiàn)策略??偟恼f來,連接池需要考慮以下問題:(1)限制連接池中最多可以容納的連接數(shù)目,避免過渡消耗系統(tǒng)資源。(2)當(dāng)客戶請求連接,而連接池中所有的連接都已經(jīng)被占用,該如何處理?一種處理方式是讓客戶一直等待,直到有空閑連接,還有一種方式是為客戶分配一個(gè)新的臨時(shí)的連接。(3)當(dāng)客戶不再使用連接,需要把連接重新放入連接池。(4)限制連接池中允許處于空閑狀態(tài)的連接的最大數(shù)目。,12.10.1創(chuàng)建連接池,例程12-19的connectionpool是連接池的接口,它聲明了取出連接、釋放連接和關(guān)閉連接池的方法。例程12-19connectionpool.javaimportjava.sql.*;publicinterfaceconnectionpool/*從連接池中取出連接*/publicconnectiongetconnection()throwssqlexception;/*把連接放回連接池*/publicvoidreleaseconnection(connectioncon)throwssqlexception;/*關(guān)閉連接池*/publicvoidclose();,12.10.1創(chuàng)建連接池,例程12-20的connectionpoolimpl類提供了一個(gè)簡單的連接池實(shí)現(xiàn),它使用以下策略:取出連接:如果連接池緩存不為空,就從中取出一個(gè)連接并將其返回,否則新建一個(gè)連接并將其返回。釋放連接:如果連接池緩存未滿,就把連接放回連接池緩存,否則就關(guān)閉該連接。關(guān)閉連接池:把連接池緩存中的所有連接關(guān)閉,再清空連接池緩存。,12.10.2datasource數(shù)據(jù)源,為了提高java應(yīng)用與連接池之間的獨(dú)立性,sun公司制定了標(biāo)準(zhǔn)的javax.sql.datasource接口,它用于封裝各種不同的連接池實(shí)現(xiàn)。凡是實(shí)現(xiàn)datasource接口的連接池都被看作標(biāo)準(zhǔn)的數(shù)據(jù)源,可以作為jndi資源發(fā)布到j(luò)ava應(yīng)用服務(wù)器(比如javaee服務(wù)器)中。datasource接口最主要的功能就是獲得數(shù)據(jù)庫連接,它的getconnection()方法提供這一服務(wù)。,12.10.2datasource數(shù)據(jù)源,12.10.2datasource數(shù)據(jù)源,假定某種應(yīng)用服務(wù)器發(fā)布了一個(gè)jndi名字為“jdbc/sampledb”的數(shù)據(jù)源,java應(yīng)用通過jndiapi中的javax.naming.context接口來獲得這個(gè)數(shù)據(jù)源的引用:contextctx=newinitialcontext();datasourceds=(datasource)ctx.lookup(java:comp/env/jdbc/sampledb);得到了datasource對象的引用后,就可以通過datasource對象的getconnection()方法獲得數(shù)據(jù)庫連接對象connection:connectioncon=ds.getconnection();,練習(xí)題1,問題:哪幾類jdbc驅(qū)動程序完全用java語言編寫?選項(xiàng):a)第1類b)第2類c)第3類d)第4類答案:c,d,練習(xí)題2,問題:以下哪些對象由connection對象創(chuàng)建?選項(xiàng):a)statement對象b)preparedstatement對象c)callablestatement對象d)resultset對象e)rowset對象答案:a,b,c,練習(xí)題3,問題:以下哪些方法屬于statement接口的方法?選項(xiàng):a)execute()b)executequery()c)executedelete()d)open()e
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 精準(zhǔn)化農(nóng)作物種植技術(shù)保證承諾書范文6篇
- 傳統(tǒng)習(xí)俗傳承承諾書(6篇)
- 員工績效評估及獎(jiǎng)懲標(biāo)準(zhǔn)表
- 企業(yè)財(cái)務(wù)報(bào)表快速解讀與分析模板
- 教育培訓(xùn)合同(在線教育職業(yè)認(rèn)證)2025年培訓(xùn)協(xié)議
- 豪放詞派知識總結(jié)
- 谷超豪課件教學(xué)課件
- 2025年山東省事業(yè)編教師類考試及答案
- 2025年廣州市人社局面試題庫及答案
- 2025年歐電云筆試題目及答案
- 旅游行業(yè)如何玩轉(zhuǎn)視頻號 從0到1開啟私域營銷
- 急腹癥影像診斷課件
- 【《紫鑫藥業(yè)財(cái)務(wù)報(bào)告審計(jì)失敗案列分析》12000字(論文)】
- 三級醫(yī)院營養(yǎng)科建設(shè)方案
- 醫(yī)院外聯(lián)部主任述職報(bào)告
- 集團(tuán)內(nèi)部融媒體管理辦法
- ASTM-D1238中文翻譯(熔融流動率、熔融指數(shù)、體積流動速率)
- 2025年浙江省寧波市鎮(zhèn)海中學(xué)高考英語模擬試卷(1月份)
- 短視頻創(chuàng)作-短視頻手機(jī)拍攝與剪輯
- 車輛掛靠駕校合同協(xié)議
- 工地盤扣打包合同協(xié)議
評論
0/150
提交評論