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

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

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

    計(jì)算機(jī)學(xué)習(xí)積累

    ----轉(zhuǎn)載有理,轉(zhuǎn)載是想研究,想研究才會(huì)看,看了才會(huì)有感想,轉(zhuǎn)載后我有時(shí)會(huì)寫(xiě)一些自己的感受
    數(shù)據(jù)加載中……

    JDBC(轉(zhuǎn))

    作者: gongshi1919 發(fā)表日期: 2006-04-08 21:59 文章屬性: 轉(zhuǎn)載 復(fù)制鏈接


    Java的數(shù)據(jù)庫(kù)連接編程(JDBC)技術(shù)

    [本講的知識(shí)要點(diǎn)]:JDBC、JDBC的工作原理,訪問(wèn)數(shù)據(jù)庫(kù)的方法、Statement、PreparedStatement、CallableStatement,ResultSet等對(duì)象的編程使用

    9.1 基本知識(shí)

    9.1.1 JDBC:Java DataBase Connectivity(Java 數(shù)據(jù)庫(kù)連接技術(shù)),它是將Java與SQL結(jié)合且獨(dú)立于特定的數(shù)據(jù)庫(kù)系統(tǒng)的應(yīng)用程序編程接口(API--它是一種可用于執(zhí)行SQL語(yǔ)句的Java API,即由一組用Java語(yǔ)言編寫(xiě)的類與接口所組成)。

    ? 有了JDBC從而可以使Java程序員用Java語(yǔ)言來(lái)編寫(xiě)完整的數(shù)據(jù)庫(kù)方面的應(yīng)用程序。另外也可以操作保存在多種不同的數(shù)據(jù)庫(kù)管理系統(tǒng)中的數(shù)據(jù),而與數(shù)據(jù)庫(kù)管理系統(tǒng)中數(shù)據(jù)存儲(chǔ)格式無(wú)關(guān)。同時(shí)Java語(yǔ)言的與平臺(tái)的無(wú)關(guān)性,不必在不同的系統(tǒng)平臺(tái)下編寫(xiě)不同的數(shù)據(jù)庫(kù)應(yīng)用程序。

    9.1.2 JDBC設(shè)計(jì)的目的

    (1)ODBC:微軟的ODBC是用C編寫(xiě)的,而且只適用于Windows平臺(tái),無(wú)法實(shí)現(xiàn)跨平臺(tái)地操作數(shù)據(jù)庫(kù)。

    (2)SQL語(yǔ)言:SQL盡管包含有數(shù)據(jù)定義、數(shù)據(jù)操作、數(shù)據(jù)管理等功能,但它并不是一個(gè)完整的編程語(yǔ)言,而且不支持流控制,需要與其它編程語(yǔ)言相配合使用。

    (3)JDBC的設(shè)計(jì):由于Java語(yǔ)言具有健壯性、安全、易使用并自動(dòng)下載到網(wǎng)絡(luò)等方面的優(yōu)點(diǎn),因此如果采用Java語(yǔ)言來(lái)連接數(shù)據(jù)庫(kù),將能克服ODBC局限于某一系統(tǒng)平臺(tái)的缺陷;將SQL語(yǔ)言與Java語(yǔ)言相互結(jié)合起來(lái),可以實(shí)現(xiàn)連接不同數(shù)據(jù)庫(kù)系統(tǒng),即使用JDBC可以很容易地把SQL語(yǔ)句傳送到任何關(guān)系型數(shù)據(jù)庫(kù)中。

    (4)JDBC設(shè)計(jì)的目的:它是一種規(guī)范,設(shè)計(jì)出它的最主要的目的是讓各個(gè)數(shù)據(jù)庫(kù)開(kāi)發(fā)商為Java程序員提供標(biāo)準(zhǔn)的數(shù)據(jù)庫(kù)訪問(wèn)類和接口,使得獨(dú)立于DBMS的Java應(yīng)用程序的開(kāi)發(fā)成為可能(數(shù)據(jù)庫(kù)改變,驅(qū)動(dòng)程序跟著改變,但應(yīng)用程序不變)。

    9.1.3 JDBC的主要功能:(1)創(chuàng)建與數(shù)據(jù)庫(kù)的連接;(2)發(fā)送SQL語(yǔ)句到任何關(guān)系型數(shù)據(jù)庫(kù)中;(3)處理數(shù)據(jù)并查詢結(jié)果。

    編程實(shí)例:

    try

    { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //(1)創(chuàng)建與數(shù)據(jù)庫(kù)的連接

    ? Connection con=DriverManager.getConnection("jdbc:odbc:DatabaseDSN","Login","Password");

    Statement stmt=con.createStatement();

    ResultSet rs=stmt.executeQuery("select * from DBTableName");//(2)發(fā)送SQL語(yǔ)句到數(shù)據(jù)庫(kù)中 ? ? ? ? ? ? ?

    while(rs.next())

    { String name=rs.getString("Name") ; ? ? ? ? //(3)處理數(shù)據(jù)并查詢結(jié)果。

    ? int age=rs.getInt("age");

    ? float wage=rs.getFloat("wage");

    }

    rs.close(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //(4)關(guān)閉

    stmt.close();

    con.close();

    }

    catch(SQLException e)

    { ? System.out.println("SQLState:"+ e.getSQLState());

    ? System.out.println("Message:" + e.getMessage());

    ? System.out.println("Vendor:" + e.getErrorCode());

    }

    9.1.4 JDBC與ODBC的對(duì)比,從而體會(huì)JDBC的特點(diǎn)

    (1)ODBC是用C語(yǔ)言編寫(xiě)的,不是面向?qū)ο蟮模欢鳭DBC是用Java編寫(xiě)的,是面向?qū)ο蟮摹?br />
    (2)ODBC難以學(xué)習(xí),因?yàn)樗押?jiǎn)單的功能與高級(jí)功能組合在一起,即便是簡(jiǎn)單的查詢也會(huì)帶有復(fù)雜的任選項(xiàng);而JDBC的設(shè)計(jì)使得簡(jiǎn)單的事情用簡(jiǎn)單的做法來(lái)完成。

    (3)ODBC是局限于某一系統(tǒng)平臺(tái)的,而JDBC提供Java與平臺(tái)無(wú)關(guān)的解決方案。

    (4)但也可以通過(guò)Java來(lái)操作ODBC,這可以采用JDBc-ODBC橋接方式來(lái)實(shí)現(xiàn)(因?yàn)镴ava不能直接使用ODBC,即在Java中使用本地C的代碼將帶來(lái)安全缺陷)。

    9.1.5 JDBC驅(qū)動(dòng)程序的類型: 目前比較常見(jiàn)的JDBC驅(qū)動(dòng)程序可分為以下四個(gè)種類:

    (1)JDBC-ODBC橋加ODBC驅(qū)動(dòng)程序

    JavaSoft橋產(chǎn)品利用ODBC驅(qū)動(dòng)程序提供JDBC訪問(wèn)。注意,必須將ODBC二進(jìn)制代碼(許多情況下還包括數(shù)據(jù)庫(kù)客戶機(jī)代碼)加載到使用該驅(qū)動(dòng)程序的每個(gè)客戶機(jī)上。因此,這種類型的驅(qū)動(dòng)程序最適合于企業(yè)網(wǎng)(這種網(wǎng)絡(luò)上客戶機(jī)的安裝不是主要問(wèn)題),或者是用Java編寫(xiě)的三層結(jié)構(gòu)的應(yīng)用程序服務(wù)器代碼。

    JDBC-ODBC 橋接方式利用微軟的開(kāi)放數(shù)據(jù)庫(kù)互連接口(ODBC API)同數(shù)據(jù)庫(kù)服務(wù)器通訊,客戶端計(jì)算機(jī)首先應(yīng)該安裝并配置ODBC driver 和JDBC-ODBC bridge兩種驅(qū)動(dòng)程序。

    (2)本地API

    這種類型的驅(qū)動(dòng)程序把客戶機(jī)API上的JDBC調(diào)用轉(zhuǎn)換為Oracle、Sybase、Informix、DB2或其它DBMS的調(diào)用。注意,象橋驅(qū)動(dòng)程序一樣,這種類型的驅(qū)動(dòng)程序要求將某些二進(jìn)制代碼加載到每臺(tái)客戶機(jī)上。

    這種驅(qū)動(dòng)方式將數(shù)據(jù)庫(kù)廠商的特殊協(xié)議轉(zhuǎn)換成Java代碼及二進(jìn)制類碼,使Java 數(shù)據(jù)庫(kù)客戶方與數(shù)據(jù)庫(kù)服務(wù)器方通信。例如:Oracle用SQLNet協(xié)議,DB2用IBM 的數(shù)據(jù)庫(kù)協(xié)議。數(shù)據(jù)庫(kù)廠商的特殊協(xié)議也應(yīng)該被安裝在客戶機(jī)上。

    (3)JDBC網(wǎng)絡(luò)純Java驅(qū)動(dòng)程序

    這種驅(qū)動(dòng)程序?qū)DBC轉(zhuǎn)換為與DBMS無(wú)關(guān)的網(wǎng)絡(luò)協(xié)議,之后這種協(xié)議又被某個(gè)服務(wù)器轉(zhuǎn)換為一種DBMS協(xié)議。這種網(wǎng)絡(luò)服務(wù)器中間件能夠?qū)⑺募僇ava客戶機(jī)連接到多種不同的數(shù)據(jù)庫(kù)上。所用的具體協(xié)議取決于提供者。通常,這是最為靈活的JDBC驅(qū)動(dòng)程序。有可能所有這種解決方案的提供者都提供適合于Intranet用的產(chǎn)品。為了使這些產(chǎn)品也支持Internet訪問(wèn),它們必須處理Web所提出的安全性、通過(guò)防火墻的訪問(wèn)等方面的額外要求。幾家提供者正將JDBC驅(qū)動(dòng)程序加到他們現(xiàn)有的數(shù)據(jù)庫(kù)中間件產(chǎn)品中。

    這種方式是純Java driver。數(shù)據(jù)庫(kù)客戶以標(biāo)準(zhǔn)網(wǎng)絡(luò)協(xié)議(如HTTP、SHTTP)同數(shù)據(jù)庫(kù)訪問(wèn)服務(wù)器通信,數(shù)據(jù)庫(kù)訪問(wèn)服務(wù)器然后翻譯標(biāo)準(zhǔn)網(wǎng)絡(luò)協(xié)議成為數(shù)據(jù)庫(kù)廠商的專有特殊數(shù)據(jù)庫(kù)訪問(wèn)協(xié)議(也可能用到ODBC driver)與數(shù)據(jù)庫(kù)通信。對(duì)Internet 和Intranet 用戶而言這是一個(gè)理想的解決方案。Java driver 被自動(dòng)的,以透明的方式隨Applets自Web服務(wù)器而下載并安裝在用戶的計(jì)算機(jī)上。

    (4)本地協(xié)議純Java驅(qū)動(dòng)程序

    這種類型的驅(qū)動(dòng)程序?qū)DBC調(diào)用直接轉(zhuǎn)換為DBMS所使用的網(wǎng)絡(luò)協(xié)議。這將允許從客戶機(jī)機(jī)器上直接調(diào)用DBMS服務(wù)器,是Intranet訪問(wèn)的一個(gè)很實(shí)用的解決方法。

    這種方式也是純Java driver。數(shù)據(jù)庫(kù)廠商提供了特殊的JDBC協(xié)議使Java數(shù)據(jù)庫(kù)客戶與數(shù)據(jù)庫(kù)服務(wù)器通信。然而,將把代理協(xié)議同數(shù)據(jù)庫(kù)服務(wù)器通信改用數(shù)據(jù)庫(kù)廠商的特殊JDBC driver。這對(duì)Intranet 應(yīng)用是高效的,可是數(shù)據(jù)庫(kù)廠商的協(xié)議可能不被防火墻支持,缺乏防火墻支持在Internet 應(yīng)用中會(huì)存在潛在的安全隱患。

    9.2 JDBC的工作原理

    ? JDBC的設(shè)計(jì)基于X/Open SQL CLI(調(diào)用級(jí)接口)這一模型。它通過(guò)定義出一組 API對(duì)象和方法以用于同數(shù)據(jù)庫(kù)進(jìn)行交互。



    在Java程序中要操作數(shù)據(jù)庫(kù),一般應(yīng)該通過(guò)如下幾步(利用JDBC訪問(wèn)數(shù)據(jù)庫(kù)的編程步驟):

    (1)加載連接數(shù)據(jù)庫(kù)的驅(qū)動(dòng)程序 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

    (2)創(chuàng)建與數(shù)據(jù)源的連接

    String url="jdbc:odbc:DatabaseDSN";

    Connection con=DriverManager.getConnection(url,"Login","Password");

    (3)查詢數(shù)據(jù)庫(kù):創(chuàng)建Statement對(duì)象并執(zhí)行SQL語(yǔ)句以返回一個(gè)ResultSet對(duì)象。

    Statement stmt=con.createStatement();

    ResultSet rs=stmt.executeQuery("select * from DBTableName");

    (4)獲得當(dāng)前記錄集中的某一記錄的各個(gè)字段的值

    ? String name=rs.getString("Name");

    ? int age=rs.getInt("age");

    ? float wage=rs.getFloat("wage");

    (5)關(guān)閉查詢語(yǔ)句及與數(shù)據(jù)庫(kù)的連接(注意關(guān)閉的順序先rs再stmt最后為con)

    ? rs.close(); ?

    ? stmt.close();

    ? con.close();

    9.3 JDBC的結(jié)構(gòu)

    ? JDBC主要包含兩部分:面向Java程序員的JDBC API及面向數(shù)據(jù)庫(kù)廠商的JDBC Drive API。

    (1)面向Java程序員的JDBC API:Java程序員通過(guò)調(diào)用此API從而實(shí)現(xiàn)連接數(shù)據(jù)庫(kù)、執(zhí)行SQL語(yǔ)句并返回結(jié)果集等編程數(shù)據(jù)庫(kù)的能力,它主要是由一系列的接口定義所構(gòu)成。

    java.sql.DriveManager:該接口主要定義了用來(lái)處理裝載驅(qū)動(dòng)程序并且為創(chuàng)建新的數(shù)據(jù)庫(kù)連接提供支持。

    java.sql.Connection:該接口主要定義了實(shí)現(xiàn)對(duì)某一種指定數(shù)據(jù)庫(kù)連接的功能。

    java.sql.Statement:該接口主要定義了在一個(gè)給定的連接中作為SQL語(yǔ)句執(zhí)行聲明的容器以實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的操作。它主要包含有如下的兩種子類型。

    ? java.sql.PreparedStatement:該接口主要定義了用于執(zhí)行帶或不帶 IN 參數(shù)的預(yù)編譯 SQL 語(yǔ)句。

    ? java.sql.CallableStatement:該接口主要定義了用于執(zhí)行數(shù)據(jù)庫(kù)的存儲(chǔ)過(guò)程的雕用。

    java.sql.ResultSet:該接口主要定義了用于執(zhí)行對(duì)數(shù)據(jù)庫(kù)的操作所返回的結(jié)果集。

    (2)面向數(shù)據(jù)庫(kù)廠商的JDBC Drive API:數(shù)據(jù)庫(kù)廠商必須提供相應(yīng)的驅(qū)動(dòng)程序并實(shí)現(xiàn)JDBC API所要求的基本接口(每個(gè)數(shù)據(jù)庫(kù)系統(tǒng)廠商必須提供對(duì)DriveManager、Connection、Statement、ResultSet等接口的具體實(shí)現(xiàn)),從而最終保證Java程序員通過(guò)JDBC實(shí)現(xiàn)對(duì)不同的數(shù)據(jù)庫(kù)操作。

    9.4 數(shù)據(jù)庫(kù)應(yīng)用的模型

    (1)兩層結(jié)構(gòu)(C/S):在此模型下,客戶端的程序直接與數(shù)據(jù)庫(kù)服務(wù)器相連接并發(fā)送SQL語(yǔ)句(但這時(shí)就需要在客戶端安裝被訪問(wèn)的數(shù)據(jù)庫(kù)的JDBC驅(qū)動(dòng)程序),DBMS服務(wù)器向客戶返回相應(yīng)的結(jié)果,客戶程序負(fù)責(zé)對(duì)數(shù)據(jù)的格式化。

    client端 ? ? ? ODBC/JDBC ? ? ? ? Server端(DBMS)

    或數(shù)據(jù)庫(kù)專用協(xié)議 ?





    主要的缺點(diǎn):受數(shù)據(jù)庫(kù)廠商的限制,用戶更換數(shù)據(jù)庫(kù)時(shí)需要改寫(xiě)客戶程序;受數(shù)據(jù)庫(kù)版本的限制,數(shù)據(jù)庫(kù)廠商一旦升級(jí)數(shù)據(jù)庫(kù),使用該數(shù)據(jù)庫(kù)的客戶程序需要重新編譯和發(fā)布;對(duì)數(shù)據(jù)庫(kù)的操作與處理都是在客戶程序中實(shí)現(xiàn),使客戶程序在編程與設(shè)計(jì)時(shí)較為復(fù)雜。



    (2)三(或多)層結(jié)構(gòu)(B/S):在此模型下,主要在客戶端的程序與數(shù)據(jù)庫(kù)服務(wù)器之間增加了一個(gè)中間服務(wù)器(可以采用C++或Java語(yǔ)言來(lái)編程實(shí)現(xiàn)),隔離客戶端的程序與數(shù)據(jù)庫(kù)服務(wù)器。客戶端的程序(可以簡(jiǎn)單為通用的瀏覽器)與中間服務(wù)器進(jìn)行通信,然后由中間服務(wù)器處理客戶端程序的請(qǐng)求并管理與數(shù)據(jù)庫(kù)服務(wù)器的連接。



    客戶端程序 HTTP RMI CORBA 中間服務(wù)器 ? JDBC ? 數(shù)據(jù)庫(kù)服務(wù)器





    9.5 通過(guò)JDBC 實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的訪問(wèn)

    (1)引用必要的包

    import java.sql.*; //它包含有操作數(shù)據(jù)庫(kù)的各個(gè)類與接口 ?

    (2)加載連接數(shù)據(jù)庫(kù)的驅(qū)動(dòng)程序類 ?

    ? 為實(shí)現(xiàn)與特定的數(shù)據(jù)庫(kù)相連接,JDBC必須加載相應(yīng)的驅(qū)動(dòng)程序類。這通常可以采用Class.forName()方法顯式地加載一個(gè)驅(qū)動(dòng)程序類,由驅(qū)動(dòng)程序負(fù)責(zé)向DriverManager登記注冊(cè)并在與數(shù)據(jù)庫(kù)相連接時(shí),DriverManager將使用此驅(qū)動(dòng)程序。

    ? ? Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

    注意:這條語(yǔ)句直接加載了sun公司提供的JDBC-ODBC Bridge驅(qū)動(dòng)程序類。

    (3)創(chuàng)建與數(shù)據(jù)源的連接

    String url="jdbc:odbc:DatabaseDSN";

    Connection con=DriverManager.getConnection(url,"Login","Password");

    注意:采用DriverManager類中的getConnection()方法實(shí)現(xiàn)與url所指定的數(shù)據(jù)源建立連接并返回一個(gè)Connection類的對(duì)象,以后對(duì)這個(gè)數(shù)據(jù)源的操作都是基于該Connection類對(duì)象;但對(duì)于Access等小型數(shù)據(jù)庫(kù),可以不用給出用戶名與密碼。

    String url="jdbc:odbc:DatabaseDSN";

    Connection con=DriverManager.getConnection(url);

    System.out.println(con.getCatalog()); //取得數(shù)據(jù)庫(kù)的完整路徑及文件名 

    ? JDBC借用了url語(yǔ)法來(lái)確定全球的數(shù)據(jù)庫(kù)(數(shù)據(jù)庫(kù)URL類似于通用的URL),對(duì)由url所指定的數(shù)據(jù)源的表示格式為

    ? jdbc::[ database locator]

    jdbc---指出要使用JDBC

    subprotocal---定義驅(qū)動(dòng)程序類型

    database locator---提供網(wǎng)絡(luò)數(shù)據(jù)庫(kù)的位置和端口號(hào)(包括主機(jī)名、端口和數(shù)據(jù)庫(kù)系統(tǒng)名等) ? jdbc:odbc://host.domain.com:port/databasefile ?

    主協(xié)議jdbc ? 驅(qū)動(dòng)程序類型為odbc,它指明JDBC管理器如何訪問(wèn)數(shù)據(jù)庫(kù),該例指名為采用JDBC-ODBC橋接方式;其它為數(shù)據(jù)庫(kù)的位置表示。 ?

    例如:裝載mySQL JDBC驅(qū)動(dòng)程序

    Class.forName("org.gjt.mm.mysql.Driver ");

    String url

    ="jdbc:mysql://localhost/softforum?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1"
      //testDB為你的數(shù)據(jù)庫(kù)名
      Connection conn= DriverManager.getConnection(url);

    例如:裝載Oracle JDBC OCI驅(qū)動(dòng)程序(用thin模式)

    Class.forName("oracle.jdbc.driver.OracleDriver ");

    String url="jdbc:oracle:thin:@localhost:1521:orcl";
      //orcl為你的數(shù)據(jù)庫(kù)的SID
      String user="scott";
      String password="tiger";
      Connection conn= DriverManager.getConnection(url,user,password);

    注意:也可以通過(guò)con.setCatalog("MyDatabase")來(lái)加載數(shù)據(jù)庫(kù)。

    例如:裝載DB2驅(qū)動(dòng)程序

    Class.forName("com.ibm.db2.jdbc.app.DB2Driver ")

    String url="jdbc:db2://localhost:5000/sample";
      //sample為你的數(shù)據(jù)庫(kù)名
      String user="admin";
      String password="";
      Connection conn= DriverManager.getConnection(url,user,password);



    例如:裝載MicroSoft SQLServer驅(qū)動(dòng)程序

    Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver ");

    String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs";
      //pubs為你的數(shù)據(jù)庫(kù)的
      String user="sa";
      String password="";   
      Connection conn= DriverManager.getConnection(url,user,password);

    (4)查詢數(shù)據(jù)庫(kù)的一些結(jié)構(gòu)信息

    ? 這主要是獲得數(shù)據(jù)庫(kù)中的各個(gè)表,各個(gè)列及數(shù)據(jù)類型和存儲(chǔ)過(guò)程等各方面的信息。根據(jù)這些信息,從而可以訪問(wèn)一個(gè)未知結(jié)構(gòu)的數(shù)據(jù)庫(kù)。這主要是通過(guò)DatabaseMetaData類的對(duì)象來(lái)實(shí)現(xiàn)并調(diào)用其中的方法來(lái)獲得數(shù)據(jù)庫(kù)的詳細(xì)信息(即數(shù)據(jù)庫(kù)的基本信息,數(shù)據(jù)庫(kù)中的各個(gè)表的情況,表中的各個(gè)列的信息及索引方面的信息)。

    ? DatabaseMetaData dbms=con.getMetaData();

    ? System.out.println("數(shù)據(jù)庫(kù)的驅(qū)動(dòng)程序?yàn)?"+dbms.getDriverName());

    (5)查詢數(shù)據(jù)庫(kù)中的數(shù)據(jù):

    ? 在JDBC中查詢數(shù)據(jù)庫(kù)中的數(shù)據(jù)的執(zhí)行方法可以分為三種類型,分別對(duì)應(yīng)Statement (用于執(zhí)行不帶參數(shù)的簡(jiǎn)單SQL語(yǔ)句字符串),PreparedStatement(預(yù)編譯SQL語(yǔ)句)和CallableStatement(主要用于執(zhí)行存儲(chǔ)過(guò)程)三個(gè)接口。

    9.5.1、實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的一般查詢Statement

    1、創(chuàng)建Statement對(duì)象(要想執(zhí)行一個(gè)SQL查詢語(yǔ)句,必須首先創(chuàng)建出Statement對(duì)象,它封裝代表要執(zhí)行的SQL語(yǔ)句)并執(zhí)行SQL語(yǔ)句以返回一個(gè)ResultSet對(duì)象,這可以通過(guò)Connection類中的createStatement()方法來(lái)實(shí)現(xiàn)。

    ? Statement stmt=con.createStatement();

    2、執(zhí)行一個(gè)SQL查詢語(yǔ)句,以查詢數(shù)據(jù)庫(kù)中的數(shù)據(jù)。Statement接口提供了三種執(zhí)行SQL語(yǔ)句的方法:executeQuery()、executeUpdate() 和execute()。具體使用哪一個(gè)方法由SQL語(yǔ)句本身來(lái)決定。

    l ? ? 方法 executeQuery 用于產(chǎn)生單個(gè)結(jié)果集的語(yǔ)句,例如 SELECT 語(yǔ)句等。

    l ? ? 方法 executeUpdate 用于執(zhí)行INSERT、UPDATE或DELETE 語(yǔ)句以及SQL DDL(數(shù)據(jù)定義語(yǔ)言)語(yǔ)句,例如 CREATE TABLE 和 DROP TABLE。INSERT、UPDATE 或DELETE 語(yǔ)句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一個(gè)整數(shù),指示受影響的行數(shù)(即更新計(jì)數(shù))。對(duì)于 CREATE TABLE 或DROP TABLE 等不操作行的語(yǔ)句,executeUpdate 的返回值總為零。

    l ? ? ? 方法 execute 用于執(zhí)行返回多個(gè)結(jié)果集、多個(gè)更新計(jì)數(shù)或二者組合的語(yǔ)句。一般不會(huì)需要該高級(jí)功能。

    下面給出通過(guò)Statement類中的executeQuery()方法來(lái)實(shí)現(xiàn)的代碼段。executeQuery()方法的輸入?yún)?shù)是一個(gè)標(biāo)準(zhǔn)的SQL查詢語(yǔ)句,其返回值是一個(gè)ResultSet類的對(duì)象。

    ResultSet rs=stmt. executeQuery ("select * from DBTableName"); ? ? ?
    要點(diǎn):①JDBC在編譯時(shí)并不對(duì)將要執(zhí)行的SQL查詢語(yǔ)句作任何檢查,只是將其作為一個(gè)String類對(duì)象,直到驅(qū)動(dòng)程序執(zhí)行SQL查詢語(yǔ)句時(shí)才知道其是否正確。對(duì)于錯(cuò)誤的SQL查詢語(yǔ)句,在執(zhí)行時(shí)將會(huì)產(chǎn)生 SQLException。

    ? ? ②一個(gè)Statement對(duì)象在同一時(shí)間只能打開(kāi)一個(gè)結(jié)果集,對(duì)第二個(gè)結(jié)果集的打開(kāi)隱含著對(duì)第一個(gè)結(jié)果集的關(guān)閉。

    ? ? ③如果想對(duì)多個(gè)結(jié)果集同時(shí)操作,必須創(chuàng)建出多個(gè)Statement對(duì)象,在每個(gè)Statement對(duì)象上執(zhí)行SQL查詢語(yǔ)句以獲得相應(yīng)的結(jié)果集。

    ? ? ④如果不需要同時(shí)處理多個(gè)結(jié)果集,則可以在一個(gè)Statement對(duì)象上順序執(zhí)行多個(gè)SQL查詢語(yǔ)句,對(duì)獲得的結(jié)果集進(jìn)行順序操作。

    import java.sql.*;

    public class ResultSetTest

    { ? public static void main(String args[])

    ? ? { ? ? try

    ? ? ? ? ? { ?

    ? ? ? ? ? ? Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

    ? ? ? ? ? ? Connection con=DriverManager.getConnection("jdbc:odbc:studlist");

    ? ? ? ? ? ? Statement stmt=con.createStatement();

    ? ? ? ? ? ? ResultSet rs1=stmt.executeQuery("select name from student");

    ? ? ? ? ? ? ResultSet rs2=stmt.executeQuery("select age from student");

    //此時(shí)rs1已經(jīng)被關(guān)閉 ? ? ? ? ? ?

    ? ? ? ? ? ? while(rs2.next())

    ? ? ? ? ? ? { ?

    ? ? ? ? ? ? ? System.out.println(rs2.getObject(1));

    ? ? ? ? ? ? }

    ? ? ? ? ? ? rs2.close();

    ? ? ? ? ? ? stmt.close();

    ? ? ? ? ? ? con.close();

    ? ? ? ? ? }

    ? ? ? ? ? catch(Exception e)

    ? ? ? ? ? {

    ? ? ? ? ? ? System.out.println(e);

    ? ? ? ? ? } ?

    ? }

    }

    注意:

    此時(shí)顯示出的將是姓名還是年齡?(將顯示的是rs2的結(jié)果集的內(nèi)容,即學(xué)生的年齡,因?yàn)椴捎肑DBC-ODBC方式的驅(qū)動(dòng)程序時(shí),并且是采用同一個(gè)Statement對(duì)象,它只會(huì)保留最新的結(jié)果集,rs1中的內(nèi)容將會(huì)被新的結(jié)果集所取代)。

    3、 關(guān)閉Statement對(duì)象:每一個(gè)Statement對(duì)象在使用完畢后,都應(yīng)該關(guān)閉。

    ? stmt.close();

    9.5.2、預(yù)編譯方式執(zhí)行SQL語(yǔ)句PreparedStatement

    ? 由于Statement對(duì)象在每次執(zhí)行SQL語(yǔ)句時(shí)都將該語(yǔ)句傳給數(shù)據(jù)庫(kù),如果需要多次執(zhí)行同一條SQL語(yǔ)句時(shí),這樣將導(dǎo)致執(zhí)行效率特別低,此時(shí)可以采用PreparedStatement對(duì)象來(lái)封裝SQL語(yǔ)句。如果數(shù)據(jù)庫(kù)支持預(yù)編譯,它可以將SQL語(yǔ)句傳給數(shù)據(jù)庫(kù)作預(yù)編譯,以后每次執(zhí)行該SQL語(yǔ)句時(shí),可以提高訪問(wèn)速度;但如果數(shù)據(jù)庫(kù)不支持預(yù)編譯,將在語(yǔ)句執(zhí)行時(shí)才傳給數(shù)據(jù)庫(kù),其效果類同于Statement對(duì)象。

    ? 另外PreparedStatement對(duì)象的SQL語(yǔ)句還可以接收參數(shù),可以用不同的輸入?yún)?shù)來(lái)多次執(zhí)行編譯過(guò)的語(yǔ)句,較Statement靈活方便(詳見(jiàn)后文介紹)。

    1、 創(chuàng)建PreparedStatement對(duì)象:從一個(gè)Connection對(duì)象上可以創(chuàng)建一個(gè)PreparedStatement對(duì)象,在創(chuàng)建時(shí)可以給出預(yù)編譯的SQL語(yǔ)句。

    ? PreparedStatement pstmt=con.prepareStatement("select * from DBTableName");

    2、 執(zhí)行SQL語(yǔ)句:可以調(diào)用executeQuery()來(lái)實(shí)現(xiàn),但與Statement方式不同的是,它沒(méi)有參數(shù),因?yàn)樵趧?chuàng)建PreparedStatement對(duì)象時(shí)已經(jīng)給出了要執(zhí)行的SQL語(yǔ)句,系統(tǒng)并進(jìn)行了預(yù)編譯。

    ? ResultSet rs=pstmt.executeQuery(); // 該條語(yǔ)句可以被多次執(zhí)行

    3、關(guān)閉PreparedStatement

    ? pstmt.close(); //其實(shí)是調(diào)用了父類Statement類中的close()方法

    9.5.3、執(zhí)行存儲(chǔ)過(guò)程CallableStatement

    ? CallableStatement類是PreparedStatement類的子類,因此可以使用在PreparedStatement類及Statement類中的方法,主要用于執(zhí)行存儲(chǔ)過(guò)程。

    1、 創(chuàng)建CallableStatement對(duì)象:使用Connection類中的prepareCall方法可以創(chuàng)建一個(gè)CallableStatement對(duì)象,其參數(shù)是一個(gè)String對(duì)象,一般格式為:

    l ? ? ? 不帶輸入?yún)?shù)的存儲(chǔ)過(guò)程“{call 存儲(chǔ)過(guò)程名()}”。

    l ? ? 帶輸入?yún)?shù)的存儲(chǔ)過(guò)程“{call存儲(chǔ)過(guò)程名(?, ?)}”

    l ? ? ? 帶輸入?yún)?shù)并有返回結(jié)果參數(shù)的存儲(chǔ)過(guò)程“{? = call 存儲(chǔ)過(guò)程名(?, ?, ...)}”

    ? CallableStatement cstmt=con.prepareCall("{call Query1()}");

    2、 執(zhí)行存儲(chǔ)過(guò)程:可以調(diào)用executeQuery()方法來(lái)實(shí)現(xiàn)。

    ? ResultSet rs=cstmt.executeQuery(); ?

    3、關(guān)閉CallableStatement

    ? cstmt.close(); //其實(shí)是調(diào)用了父類Statement類中的close()方法

    (6)檢索記錄集以獲得當(dāng)前記錄集中的某一記錄的各個(gè)字段的值

    9.5.4、ResultSet對(duì)象:

    ? ① 執(zhí)行完畢SQL語(yǔ)句后,將返回一個(gè)ResultSet類的對(duì)象,它包含所有的查詢結(jié)果。但對(duì)ResultSet類的對(duì)象方式依賴于光標(biāo)(Cursor)的類型,而對(duì)每一行中的各個(gè)列,可以按任何順序進(jìn)行處理(當(dāng)然,如果按從左到右的順序?qū)Ω髁羞M(jìn)行處理可以獲得較高的執(zhí)行效率);

    ResultSet類中的Course方式主要有:

    ResultSet.TYPE_FORWARD_ONLY(為缺省設(shè)置):光標(biāo)只能前進(jìn)不能后退,也就是只能從第一個(gè)一直移動(dòng)到最后一個(gè)。

    ResultSet.TYPE_SCROLL_SENSITIVE:允許光標(biāo)前進(jìn)或后退并感應(yīng)到其它ResultSet的光標(biāo)的移動(dòng)情形。

    ResultSet.TYPE_SCROLL_INSENSITIVE:允許光標(biāo)前進(jìn)或后退并不能感應(yīng)到其它ResultSet的光標(biāo)的移動(dòng)情形。

    ResultSet類中的數(shù)據(jù)是否允許修改主要有:

    ResultSet.CONCUR_READ_ONLY(為缺省設(shè)置):表示數(shù)據(jù)只能只讀,不能更改。

    ResultSet.CONCUR_UPDATABLE:表示數(shù)據(jù)允許被修改。

    ? 可以在創(chuàng)建Statement或PreparedStatement對(duì)象時(shí)指定ResultSet的這兩個(gè)特性。

    Statement stmt=con.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);



    PreparedStatement pstmt=con.PrepareStatement("insert into bookTable values (?,?,?)",ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);

    ? ② ResultSet類的對(duì)象維持一個(gè)指向當(dāng)前行的指針,利用ResultSet類的next()方法可以移動(dòng)到下一行(在JDBC中,Java程序一次只能看到一行數(shù)據(jù)),如果next()的返回值為false,則說(shuō)明已到記錄集的尾部。另外JDBC也沒(méi)有類似ODBC 的書(shū)簽功能的方法。

    ? ③ 利用ResultSet類的getXXX()方法可以獲得某一列的結(jié)果,其中XXX代表JDBC中的Java數(shù)據(jù)類型,如 getInt()、getString()、getDate()等。訪問(wèn)時(shí)需要指定要檢索的列(可以采用 int值作為列號(hào)(從1開(kāi)始計(jì)數(shù))或指定列(字段)名方式,但字段名不區(qū)別字母的大小寫(xiě))。

    while(rs.next())

    { String name=rs.getString("Name"); //采用“列名”的方式訪問(wèn)數(shù)據(jù)

    ? int age=rs.getInt("age");

    ? float wage=rs.getFloat("wage");

    ? String homeAddress=rs.getString(4); //采用“列號(hào)”的方式訪問(wèn)數(shù)據(jù)

    }

    9.5.5、數(shù)據(jù)轉(zhuǎn)換

    ? 利用ResultSet類的getXXX()方法可以實(shí)現(xiàn)將ResultSet中的SQL數(shù)據(jù)類型轉(zhuǎn)換為它所返回的Java數(shù)據(jù)類型。

    9.5.6、NULL結(jié)果值

      要確定給定結(jié)果值是否是JDBC NULL,必須先讀取該列,然后使用ResultSet.wasNull

    方法檢查該次讀取是否返回JDBC NULL。

      當(dāng)使用ResultSet.getXXX方法讀取JDBC NULL時(shí),方法wasNull將返回下列值之一:

    (1)Javanull值

      對(duì)于返回Java對(duì)象的getXXX方法(例如getString、getBigDecimal、getBytes、getDate、getTime、getTimestamp、getAsciiStream、getUnicodeStream、getBinaryStream、getObject等)。

    (2)零值:對(duì)于getByte、getShort、getInt、getLong、getFloat和getDouble。

    (3)false值:對(duì)于getBoolean

    9.5.6、獲得結(jié)果集中的結(jié)構(gòu)信息:利用ResultSet類的getMetaData()方法來(lái)獲得結(jié)果集中的一些結(jié)構(gòu)信息(主要提供用來(lái)描述列的數(shù)量、列的名稱、列的數(shù)據(jù)類型。利用ResulSetMetaData類中的方法)。

    ResultsetMetaData rsmd=rs.getMetaData();

    rsmd.getColumnCount(); ? //返回結(jié)果集中的列數(shù) ? ? ? ?

    rsmd.getColumnLabel(1); //返回第一列的列名(字段名)

    例如:

    Statement stmt=con.createStatement();

    ResultSet rs=stmt.executeQuery("select * from TableName");

    for(int i=1; i<=rs.getMetaData().getColumnCount(); i++) ? //跟蹤顯示各個(gè)列的名稱

    ? ? { ? ? System.out.print(rs. getColumnName (i)+"\t");

    ? ? }

    while(rs.next())

    { //跟蹤顯示各個(gè)列的值

    ? for(int j=1; j<=rs.getMetaData().getColumnCount(); j++)

    ? ? { ? ? System.out.print(rs.getObject(j)+"\t");

    ? ? }

    }

    9.6、更新數(shù)據(jù)庫(kù)

    ? 前面主要介紹如何實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的查詢操作,但在許多應(yīng)用中需要實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的更新,這主要涉及修改、插入和刪除等(即SQL語(yǔ)句中的Insert、Update、Delete、Creat、Drap等)。仍然通過(guò)創(chuàng)建Statement對(duì)象來(lái)實(shí)現(xiàn),但不再調(diào)用executeQuery()方法,而是使用executeUpdate()方法。

    要點(diǎn)F:正確區(qū)分Statement類中的executeQuery()、execute()和executeUpdate()方法的用法:(1)

    executeQuery() 執(zhí)行一般的SQL查詢語(yǔ)句(即SELECT語(yǔ)句)并返回Resultset對(duì)象;(2)execute()可以執(zhí)行各種SQL查詢語(yǔ)句,并可能返回多個(gè)結(jié)果集(這一般主要發(fā)生在執(zhí)行了返回多個(gè)結(jié)果集的存儲(chǔ)過(guò)程時(shí)),此時(shí)可以采用Resultset類的getResultSet()來(lái)獲得當(dāng)前的結(jié)果集;(3)executeUpdate()執(zhí)行對(duì)數(shù)據(jù)庫(kù)的更新的SQL語(yǔ)句或DDL語(yǔ)句。

    9.6.1 對(duì)表中的記錄進(jìn)行操作

    ? 對(duì)一個(gè)表中的記錄可以進(jìn)行修改、插入和刪除等操作,分別對(duì)應(yīng)SQL的Update、 Insert、Delete操作;executeUpdate()方法的輸入?yún)?shù)仍然為一個(gè)String對(duì)象(即所要執(zhí)行的SQL語(yǔ)句),但輸出參數(shù)不是ResultSet對(duì)象,而是一個(gè)整數(shù)(它代表操作所影響的記錄行數(shù))。

    Statement stmt=con.createStatement();

    stmt.executeUpdate("Update bookTable set Title='Java2' where Author='zhang'");



    stmt.executeUpdate("Delete from bookTable where Author='zhang'");

    stmt.executeUpdate("Insert into bookTable(BookID,Author,Title) values(1,'Li Ming','Java2')"); //未給出的列,其值為NULL



    程序?qū)嵗簩?duì)數(shù)據(jù)庫(kù)中的表進(jìn)行更新操作并顯示操作前后的結(jié)果

    import java.sql.*;

    public class DBUpdateSetTest

    { ? public static void main(String args[])

    ? ? { ? ? try

    ? ? ? ? ? { ?

    ? ? ? ? ? ? Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

    ? ? ? ? ? ? Connection con=DriverManager.getConnection("jdbc:odbc:studlist");

    ? ? ? ? ? ? Statement stmt=con.createStatement();

    ? ? ? ? ? ? ResultSet rs=stmt.executeQuery("select * from student");

    ? ? ? ? ? ? System.out.println("Result before executeUpdate");

    ? ? ? ? ? ? while(rs.next())

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? System.out.println(rs.getString("name"));

    ? ? ? ? ? ? ? ? System.out.println(rs.getString("age"));

    ? ? ? ? ? ? }

    ? ? ? ? ? ? stmt.executeUpdate("Update student set name='Yang' where id=0");

    ? ? ? ? ? ? stmt.executeUpdate("Delete from student where id=2");

    ? ? ? ? ? ? stmt.executeUpdate("Insert into student(id,name,age,sex) values(2,'zhang',30,true)");

    ? ? ? ? ? ? rs=stmt.executeQuery("select * from student");

    ? ? ? ? ? ? System.out.println("Result After executeUpdate");

    ? ? ? ? ? ? while(rs.next())

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? System.out.println(rs.getString("name"));

    ? ? ? ? ? ? ? ? System.out.println(rs.getString("age"));

    ? ? ? ? ? ? }

    ? ? ? ? ? ? rs.close();

    ? ? ? ? ? ? stmt.close();

    ? ? ? ? ? ? con.close();

    ? ? ? ? ? ? }

    ? ? ? ? ? catch(Exception e)

    ? ? ? ? ? {

    ? ? ? ? ? ? System.out.println(e);

    ? ? ? ? ? } ?

    ? ? }

    }

    9.6.2 創(chuàng)建和刪除表

    ? 創(chuàng)建和刪除一個(gè)表主要對(duì)應(yīng)于SQL的Create Table和Drop Table語(yǔ)句。這可以通過(guò)Statement對(duì)象的executeUpdate()方法來(lái)完成。

    ① 創(chuàng)建表

    ? Statement stmt=con.createStatement();

    ? stmt.executeUpdate("create table TableName(ID integer, Name VARCHAR(20), Age integer)");

    ? stmt.executeUpdate("Insert into TableName(ID, Name, Age) values(1,'Yang Ming',30)");

    ② 刪除表

    ? Statement stmt=con.createStatement();

    ? stmt.executeUpdate("Drop Table TableName");

    9.6.3 增加和刪除表中的列

    對(duì)一個(gè)表的列進(jìn)行更新操作主要是使用SQL的ALTER Table語(yǔ)句。對(duì)列所進(jìn)行的更新操作會(huì)影響到表中的所有的行。

    ① 增加表中的一列

    ? Statement stmt=con.createStatement();

    ? stmt.executeUpdate("Alter Table TableName add Column Address VarChar(50)");

    ? stmt.executeUpdate("Update TableName set Address='Beijing,China' where ID=1");

    ② 刪除表中的一列

    ? Statement stmt=con.createStatement();

    ? stmt.executeUpdate("Alter Table TableName Drop Column Address");

    ? stmt.executeQuery("Select * from TableName");

    9.6.4 利用PreparedStatement對(duì)象實(shí)現(xiàn)數(shù)據(jù)更新

    ? 同SQL查詢語(yǔ)句一樣,對(duì)數(shù)據(jù)更新語(yǔ)句時(shí)也可以在PreparedStatement對(duì)象上執(zhí)行。使用PreparedStatement對(duì)象,只需傳遞一次SQL語(yǔ)句,可以多次執(zhí)行它,并且可以利用數(shù)據(jù)庫(kù)的預(yù)編譯技術(shù),提高執(zhí)行效率。另外也可以接受參數(shù)。

    ? PreparedStatement pstmt=con.prepareStatement("Update TableName set Address='Beijing,China' where ID >1");

    ? pstmt.executeUpdate();

    9.7 參數(shù)的輸入與輸出

    ? 要實(shí)現(xiàn)使用SQL語(yǔ)句的輸入與輸出參數(shù),必須在PreparedStatement類的對(duì)象上進(jìn)行操作;同時(shí)由于CallableStatement類是PrepareStatement類的子類,所以在CallableStatemen對(duì)象上的操作也可以使用輸入與輸出參數(shù);其主要的編程原理是在生成CallableStatement或PreparedStatement類的對(duì)象時(shí),可以在SQL語(yǔ)句中指定輸入或輸出參數(shù),在執(zhí)行這個(gè)SQL語(yǔ)句之前,要對(duì)輸入?yún)?shù)進(jìn)行賦值。

    (1)使用PreparedStatement類的對(duì)象

    ? 通過(guò)prepareStatement類的對(duì)象可以實(shí)現(xiàn)在查詢語(yǔ)句與數(shù)據(jù)更新語(yǔ)句方面都可以設(shè)置輸入?yún)?shù)。

    ? 具體的方法是在SQL語(yǔ)句中用“?”標(biāo)明參數(shù),在執(zhí)行SQL語(yǔ)句之前,使用setXXX方法給參數(shù)賦值,然后使用executeQuery()或executeUpdate()來(lái)執(zhí)行這個(gè)SQL語(yǔ)句。每次執(zhí)行SQL語(yǔ)句之前,可以給參數(shù)重新賦值。

    ? setXXX方法用于給相應(yīng)的輸入?yún)?shù)進(jìn)行賦值,其中XXX是JDBC的數(shù)據(jù)類型,如:Int、String等。setXXX方法有兩個(gè)參數(shù),第一個(gè)是要賦值的參數(shù)在SQL語(yǔ)句中的位置, SQL語(yǔ)句中的第一個(gè)參數(shù)的位置為1,第二個(gè)參數(shù)的位置為2;setXXX方法的第二個(gè)參數(shù)是要傳遞的值,如100、“Peking”等,隨XXX的不同而為不同的類型。

    ? PreparedStatement pstmt=con.prepareStatement("Update TableName set Name=? where ID=?");

    ? pstmt.setString(1,"zhang Hua"); //設(shè)置第一個(gè)參數(shù)(Name)為 “zhang Hua”

    ? for(int i=1;i<3;i++)

    ? { pstmt.setInt(2,i); //設(shè)置第二個(gè)參數(shù)(ID)為 1,2

    ? ? pstmt.executeUpdate();

    ? }

    要點(diǎn):最終實(shí)現(xiàn) Update TableName set Name=zhang Hua where ID=1 與Update TableName set Name=zhang Hua where ID=2的效果。

    (2)使用CallableStatement對(duì)象

    ? 如果要求調(diào)用數(shù)據(jù)庫(kù)的存儲(chǔ)過(guò)程,要使用CallableStatement對(duì)象。另外還有些存儲(chǔ)過(guò)程要求用戶輸入?yún)?shù),這可以在生成CallableStatement對(duì)象的存儲(chǔ)過(guò)程調(diào)用語(yǔ)句中設(shè)置輸入?yún)?shù)。在執(zhí)行這個(gè)存儲(chǔ)過(guò)程之前使用setXXX方法給參數(shù)賦值,然后再執(zhí)行這個(gè)存儲(chǔ)過(guò)程。

    ? CallableStatement cstmt=con.prepareCall("{call Query(?)}"); //Query為存儲(chǔ)過(guò)程名

    ? cstmt.setString(1,"輸入?yún)?shù)"); //為存儲(chǔ)過(guò)程提供輸入?yún)?shù)

    ? ResultSet rs=cstmt.executeQuery();

    (3)接收輸出參數(shù)

    ? 某些存儲(chǔ)過(guò)程可能會(huì)返回輸出參數(shù),這時(shí)在執(zhí)行這個(gè)存儲(chǔ)過(guò)程之前,必須使用CallableStatement的registerOutParameter方法首先登記輸出參數(shù),在registerOutParameter方法中要給出輸出參數(shù)的相應(yīng)位置以及輸出參數(shù)的SQL數(shù)據(jù)類型。在執(zhí)行完存儲(chǔ)過(guò)程以后,必須使用getXXX方法來(lái)獲得輸出參數(shù)的值。并在getXXX方法中要指出獲得哪一個(gè)輸出參數(shù)(通過(guò)序號(hào)來(lái)指定)的值。

    實(shí)例:存儲(chǔ)過(guò)程getTestData有三個(gè)輸入?yún)?shù)并返回一個(gè)輸出參數(shù),類型分別為VARCHAR。在執(zhí)行完畢后,分別使用getString()方法來(lái)獲得相應(yīng)的值。

    CallableStatement cstmt = con.prepareCall(“{? = call getTestData (?,?,?)}”);

    cstmt.setString(1,Value); ? ? ? ? ? ? ? ? ? ? ? //設(shè)置輸入?yún)?shù)

    cstmt.setInt(2,Value);

    cstmt.setFloat(3,Value);

    cstmt.registerOutParameter(1,java.sql.Types.VARCHAR); ? //登記輸出參數(shù)

    ResultSet rs = cstmt.executeQuery(); ? ? ? ? //執(zhí)行存儲(chǔ)過(guò)程

    rs.getString(1); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //獲得第一個(gè)字段的值

    String returnResult=cstmt.getString(1); ? ? ? ? ? ? ? //獲得返回的輸出參數(shù)的值

    要點(diǎn):由于getXXX方法不對(duì)數(shù)據(jù)類型作任何轉(zhuǎn)換,在registerOutParameter方法中指明數(shù)據(jù)庫(kù)將返回的SQL數(shù)據(jù)類型,在執(zhí)行完存儲(chǔ)過(guò)程以后必須采用相應(yīng)匹配的getXXX方法來(lái)獲得輸出參數(shù)的值。



    9.8 批量處理JDBC語(yǔ)句提高處理速度



    有時(shí)候JDBC運(yùn)行得不夠快,這可以使用數(shù)據(jù)庫(kù)相關(guān)的存儲(chǔ)過(guò)程。當(dāng)然,作為存儲(chǔ)過(guò)程的一個(gè)替代方案,可以試試使用Statement 的批量處理特性以提高速度。



      存儲(chǔ)過(guò)程的最簡(jiǎn)單的形式就是包含一系列SQL語(yǔ)句的過(guò)程,將這些語(yǔ)句放在一起便于在同一個(gè)地方管理也可以提高速度。Statement 類可以包含一系列SQL語(yǔ)句,因此允許在同一個(gè)數(shù)據(jù)庫(kù)事務(wù)執(zhí)行所有的那些語(yǔ)句而不是執(zhí)行對(duì)數(shù)據(jù)庫(kù)的一系列調(diào)用。

      使用批量處理功能涉及下面的兩個(gè)方法:

      addBatch(String) 方法

      executeBatch方法

      如果你正在使用Statement 那么addBatch 方法可以接受一個(gè)通常的SQL語(yǔ)句,或者如果你在使用PreparedStatement ,那么也可以什么都不向它增加。

    executeBatch 方法執(zhí)行那些SQL語(yǔ)句并返回一個(gè)int值的數(shù)組,這個(gè)數(shù)組包含每個(gè)語(yǔ)句影響的數(shù)據(jù)的行數(shù)。

    注意:如果將一個(gè)SELECT語(yǔ)句或者其他返回一個(gè)ResultSet的SQL語(yǔ)句放入批量處理中就會(huì)導(dǎo)致一個(gè)SQLException異常。

      關(guān)于java.sql.Statement 的簡(jiǎn)單范例可以是:

    ? ? con = DriverManager.getConnection(url,"myLogin", "myPassword");

    ? ? con.setAutoCommit(false);

    ? ? stmt = con.createStatement();

    ? ? stmt.addBatch("INSERT INTO student " + "VALUES(4,'Yang',20,True)");

    ? ? stmt.addBatch("INSERT INTO student " + "VALUES(5,'li',20,True)");

    ? ? stmt.addBatch("INSERT INTO student " + "VALUES(6,'zhang',20,True)");

    ? ? stmt.addBatch("INSERT INTO student " + "VALUES(7,'wang',20,True)");

    ? ? stmt.addBatch("INSERT INTO student " + "VALUES(8,'liu',20,True)");



    ? ? int [] updateCounts = stmt.executeBatch();

    ? ? con.commit();

    ? ? con.setAutoCommit(true);



     PreparedStatement 有些不同,它只能處理一部分SQL語(yǔ)法,但是可以有很多參數(shù),因此重寫(xiě)上面的范例的一部分就可以得到下面的結(jié)果:

     // 注意這里沒(méi)有刪除語(yǔ)句

    PreparedStatement stmt = conn.prepareStatement(

    "INSERT INTO student VALUES(?,?,?,?)"

    );

    User[ ] users = ...;

    for(int i=0; i

    stmt.setInt(1, users
    .getID());

    stmt.setString(2, users
    .getName());

    stmt.setInt(3, users
    .getAge());

    stmt.setBoolean(4, users
    .getSex());

    stmt.addBatch( );

    }

    int[ ] counts = stmt.executeBatch();

    如果你不知道你的語(yǔ)句要運(yùn)行多少次,那么這是一個(gè)很好的處理SQL代碼的方法。在不使用批量處理的情況下,如果添加50個(gè)用戶,那么性能就有影響,如果某個(gè)人寫(xiě)了一個(gè)腳本添加一萬(wàn)個(gè)用戶,程序可能變得很糟糕。添加批處理功能就可以幫助提高性能,而且在后面的那種情況下代碼的可讀性也會(huì)更好。

    posted on 2006-08-24 13:36 freebird 閱讀(389) 評(píng)論(0)  編輯  收藏 所屬分類: java

    主站蜘蛛池模板: 67pao强力打造高清免费| 精品国产综合成人亚洲区| 久久午夜伦鲁片免费无码| 国产精品久久久久久亚洲小说| 7777久久亚洲中文字幕蜜桃 | 日韩亚洲变态另类中文| 性感美女视频免费网站午夜| 午夜无码A级毛片免费视频| 黄网站色成年片大免费高清| 亚洲成人激情小说| 亚洲电影免费观看| 亚洲成a人片77777kkkk| 久久精品国产亚洲Aⅴ香蕉| 国产精品免费视频网站| 免费无码AV电影在线观看| 亚洲一级免费视频| 无码精品国产一区二区三区免费| 国产精品免费久久久久电影网| 精品国产亚洲AV麻豆| 亚洲av无码一区二区三区四区| 亚洲AV成人无码天堂| 亚洲国产综合在线| 亚洲综合无码一区二区三区| 亚洲AV无码专区电影在线观看| 伊人久久大香线蕉亚洲五月天| 成人伊人亚洲人综合网站222| 国产成人一区二区三区免费视频| 最近中文字幕免费mv视频8| 国产一卡2卡3卡4卡无卡免费视频| 99在线热视频只有精品免费| 久久久久久免费一区二区三区| 中国一级特黄的片子免费 | 亚洲av日韩片在线观看| 国产特级淫片免费看| 免费观看国产精品| 免费少妇a级毛片| 波多野结衣一区二区免费视频| 免费人成在线观看网站视频| 九月婷婷亚洲综合在线| 亚洲日韩人妻第一页| 亚洲中文字幕在线观看|