小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

使用JDBC連接數(shù)據(jù)庫 - 《Java JDK 6學(xué)習(xí)筆記》

 iversion 2007-08-02

JDBC(Java DataBase Connectivity)是使用Java存取數(shù)據(jù)庫系統(tǒng)的解決方案,它將不同數(shù)據(jù)庫間各自差異API與標(biāo)準(zhǔn)SQL(Structured Query Language)語句分開看待,實現(xiàn)數(shù)據(jù)庫無關(guān)的Java操作接口。開發(fā)人員使用JDBC統(tǒng)一的API接口,并專注于標(biāo)準(zhǔn)SQL語句,就可以避免直接處理底層數(shù)據(jù)庫驅(qū)動程序與相關(guān)操作接口的差異性。

實際的數(shù)據(jù)庫存取是個非常復(fù)雜的主題,可以使用專書加以說明,不過在本章中,會告訴您一些JDBC基本API的使用與概念,讓您對Java如何存取數(shù)據(jù)庫有所認(rèn)識。

20.1 使用JDBC連接數(shù)據(jù)庫

在正式使用JDBC進行數(shù)據(jù)庫操作之前,先來認(rèn)識JDBC的基本架構(gòu),了解數(shù)據(jù)庫驅(qū)動程序與數(shù)據(jù)庫之間的關(guān)系。在這個小節(jié)也將看到,如何設(shè)計一個簡單的工具類,讓您在進行數(shù)據(jù)庫連接(Connection)時更為方便。

20.1.1 簡介JDBC

如果要連接數(shù)據(jù)庫并進行操作,基本上必須了解數(shù)據(jù)庫所提供的API操作接口,然而各個廠商所提供的API操作界面并不一致,如果今天要使用A廠商的數(shù)據(jù)庫,就必須設(shè)計一個專用的程序來操作A廠商數(shù)據(jù)庫所提供的API,將來如果要使用B廠商的數(shù)據(jù)庫,即使上層應(yīng)用程序本身的目的相同,也是要編寫專用于B廠商數(shù)據(jù)庫之存取程序,十分的不方便。

使用JDBC,可由廠商操作實現(xiàn)操作數(shù)據(jù)庫接口的驅(qū)動程序,而Java程序設(shè)計人員調(diào)用JDBC的API并操作SQL,實際對數(shù)據(jù)庫的操作由JDBC驅(qū)動程序負責(zé)。如果要更換數(shù)據(jù)庫,基本上只要更換驅(qū)動程序,Java程序中只要加載新的驅(qū)動程序來源,即可完成數(shù)據(jù)庫系統(tǒng)的變更,Java 程序的部分則無需改變。

圖20-1是JDBC API、數(shù)據(jù)庫驅(qū)動程序與數(shù)據(jù)庫之間的關(guān)系:

圖20-1  應(yīng)用程序、JDBC與驅(qū)動程序之間的關(guān)系

簡單地說,JDBC希望達到的目的,是讓Java程序設(shè)計人員在編寫數(shù)據(jù)庫操作程序的時候,可以有個統(tǒng)一的操作接口,無需依賴于特定的數(shù)據(jù)庫API,希望達到“寫一個Java程序,適用所有的數(shù)據(jù)庫”的目的。

JDBC數(shù)據(jù)庫驅(qū)動程序按實現(xiàn)方式可以分為4個類型:

   Type 1:JDBC-ODBC Bridge

用戶的計算機上必須事先安裝好ODBC驅(qū)動程序,Type 1驅(qū)動程序利用橋接(Bridge)方式,將JDBC的調(diào)用方式轉(zhuǎn)換為ODBC驅(qū)動程序的調(diào)用方式,如圖20-2所示,Microsoft Access數(shù)據(jù)庫存取就是使用這種類型。

圖20-2  Type 1: JDBC-ODBC Bridge

   Type 2:Native-API Bridge

Type 2驅(qū)動程序利用橋接方式,驅(qū)動程序上層封裝Java程序以與Java應(yīng)用程序作溝通,將JDBC調(diào)用轉(zhuǎn)為本地(Native)程序代碼的調(diào)用,下層為本地語言(就像C、C++)來與數(shù)據(jù)庫進行溝通,下層的函數(shù)庫是針對特定數(shù)據(jù)庫設(shè)計的,不像Type 1可以對ODBC架構(gòu)的數(shù)據(jù)庫進行存取,如圖20-3所示。

圖20-3  Type 2: Native-API Bridge

   Type 3:JDBC-middleware

通過中間件(middleware)來存取數(shù)據(jù)庫,用戶不必安裝特定的驅(qū)動程序,而是調(diào)用中間件,由中間件來完成所有的數(shù)據(jù)庫存取動作,然后將結(jié)果返回給應(yīng)用程序,如圖20-4所示。

圖20-4  Type 3: JDBC-moddleware

   Type 4:Pure Java Driver

使用純Java程序來編寫驅(qū)動程序與數(shù)據(jù)庫進行溝通,而不通過橋接或中間件來存取數(shù)據(jù)庫,如圖20-5所示。

圖20-5  Type 4: Pure Java Driver

在接下來的內(nèi)容中,將使用MySQL數(shù)據(jù)庫系統(tǒng)進行操作。MySQL的JDBC驅(qū)動程序?qū)儆赥ype 4。您可以在以下的網(wǎng)址獲得MySQL的JDBC驅(qū)動程序,本章中將使用MySQL Connector/J 5.0。

http://www./products/connector/j/index.html

                                 

 

關(guān)于數(shù)據(jù)庫系統(tǒng)的使用與操作是個很大的主題,本書中并不針對這方面加以介紹,請尋找數(shù)據(jù)庫系統(tǒng)相關(guān)書籍自行學(xué)習(xí),不過為了讓您能順利練習(xí)本章的范例,附錄C中包括了一個MySQL數(shù)據(jù)庫系統(tǒng)的簡介,足夠您了解這一章中將用到的一些數(shù)據(jù)庫操作命令。

20.1.2 連接數(shù)據(jù)庫

為了要連接數(shù)據(jù)庫系統(tǒng),您必須要有JDBC驅(qū)動程序,由于接下來將使用MySQL數(shù)據(jù)庫進行操作,所以請將下載的tar.gz文件使用解壓縮軟件解開,并將其中的mysql-connector-java-*.jar加入至Classpath的設(shè)置之中,假設(shè)是放在c:\workspace\library\mysql-connector-java-5.0.3-bin.jar,則Classpath中必須有c:\workspace\library\mysql-connector-java-5.0.3-bin.jar這個路徑設(shè)置。

在Java SE中與數(shù)據(jù)庫操作相關(guān)的JDBC類都位于java.sql包中,要連接數(shù)據(jù)庫,基本上必須有以下幾個動作。

   加載JDBC驅(qū)動程序

首先必須通過java.lang.Class類的forName()動態(tài)加載驅(qū)動程序類,并向DriverManager注冊JDBC驅(qū)動程序(驅(qū)動程序會自動通過DriverManager.registerDriver()方法注冊)。MySQL的驅(qū)動程序類是com.mysql.jdbc.Driver,一個加載JDBC驅(qū)動程序的程序片段如下所示:

try {
    Class.forName("com.mysql.jdbc.Driver");
}
catch(ClassNotFoundException e) {
    System.out.println("找不到驅(qū)動程序類");
}

   提供JDBC URL

JDBC URL定義了連接數(shù)據(jù)庫時的協(xié)議、子協(xié)議、數(shù)據(jù)源識別。

協(xié)定:子協(xié)定:數(shù)據(jù)源識別

“協(xié)議”在JDBC中總是jdbc開始;“子協(xié)議”是橋接的驅(qū)動程序或是數(shù)據(jù)庫管理系統(tǒng)名稱,使用MySQL的話是 "mysql";“數(shù)據(jù)源識別”標(biāo)出找出數(shù)據(jù)庫來源的地址與連接端口。舉個例子來說,MySQL的JDBC URL編寫方式如下:

jdbc:mysql://主機名稱:連接端口/數(shù)據(jù)庫名稱?參數(shù)=值&參數(shù)=值

主機名稱可以是本機localhost或是其他連接主機,連接端口為3306,假如要連接demo數(shù)據(jù)庫,并指明用戶名稱與密碼,可以如下指定:

jdbc:mysql://localhost:3306/demo?user=root&password=123

如果要使用中文存取的話,還必須給定參數(shù)useUnicode及characterEncoding,表明是否使用Unicode,并指定字符編碼方式,例如:

jdbc:mysql://localhost:3306/demo?user=root&password=123&useUnicode=true&characterEncoding=Big5

   獲得Connection

要連接數(shù)據(jù)庫,可以向java.sql.DriverManager要求并獲得java.sql.Connection對象。Connection是數(shù)據(jù)庫連接的具體代表對象,一個Connection對象就代表一個數(shù)據(jù)庫連接,您可以使用DriverManager的getConneciton()方法,指定JDBC URL作為自變量并獲得Connection對象:

try {
    String url =  "jdbc:mysql://localhost:3306/demo?" +
                     "user=root&password=123";
    Connection conn = DriverManager.getConnection(url);
    ....
}
catch(SQLException e) {
    ....
}

java.sql.SQLException是在處理JDBC時經(jīng)常遇到的異常對象,SQLException是受檢異常 (Checked Exception),您必須使用try...catch或throws明確處理,它表示JDBC操作過程中若發(fā)生錯誤時的具體對象代表。

獲得Connection對象之后,可以使用isClosed()方法測試與數(shù)據(jù)庫的連接是否關(guān)閉,在操作完數(shù)據(jù)庫之后,如果確定不再需要連接,則必須使用close()來關(guān)閉與數(shù)據(jù)庫的連接,以釋放連接時相關(guān)的必要資源。

getConnection()方法可以在參數(shù)上指定用戶名稱與密碼,例如:

String url = "jdbc:mysql://localhost:3306/demo";
String user = "root";
String password = "123";
Connection conn = DriverManager.getConnection(url,
                                         user, password);

20.1.3 簡單的Connection工具類

在20.1.2節(jié)獲得Connection的程序片段中,您可以看到其中直接用字符串在程序中寫下JDBC URL、用戶名稱與密碼等信息,實際的程序并不會將這些敏感信息寫在程序代碼之中,而且這么做的話,如果要更改用戶名稱或密碼時,還要修改程序、重新編譯,在程序維護上并不方便。

您可以將JDBC URL、用戶名稱與密碼等設(shè)置信息編寫在一個屬性文件中,由程序讀取這個屬性文件中的信息,如果需要變更信息,則只要修改屬性文件,無須修改程序、重新編譯。在Java SE中,屬性文件的讀取可以交給java.util.Properties類。

舉個實際的例子,假設(shè)您使用了以下命令在MySQL中建立了demo數(shù)據(jù)庫:

CREATE DATABASE demo;

由于獲得Connection的方式,按所使用的環(huán)境及程序需求而有所不同,因而您可以先設(shè)計一個DBSource接口,規(guī)范獲得Connection的方法,如范例20.1所示。

Ü 范例20.1  DBSource.java

package onlyfun.caterpillar;

import java.sql.Connection;

import java.sql.SQLException;

public interface DBSource {

    public Connection getConnection() throws SQLException;

    public void closeConnection(Connection conn) throws SQLException;

}

接著可以實現(xiàn)DBSource接口,您的目的是從屬性文件中讀取設(shè)置信息、加載JDBC驅(qū)動程序,可以通過getConnection()方法獲得Connection對象,并通過closeConnection()方法關(guān)閉Connection對象,在這里以一個簡單的SimpleDBSource類作為示范,如范例20.2所示。

Ü 范例20.2  SimpleDBSource.java

package onlyfun.caterpillar;

import java.io.FileInputStream;

import java.io.IOException;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.util.Properties;

public class SimpleDBSource implements DBSource {

    private Properties props;

    private String url;

    private String user;

    private String passwd;

    public SimpleDBSource() throws IOException,

                                         ClassNotFoundException {

        this("jdbc.properties");

    }

     

    public SimpleDBSource(String configFile) throws IOException,

                                                    ClassNotFoundException {

        props = new Properties();

        props.load(new FileInputStream(configFile));

              

        url = props.getProperty("onlyfun.caterpillar.url");

        user = props.getProperty("onlyfun.caterpillar.user");

        passwd = props.getProperty("onlyfun.caterpillar.password");

              

        Class.forName(

                    props.getProperty("onlyfun.caterpillar.driver"));

    }

    public Connection getConnection() throws SQLException {

        return DriverManager.getConnection(url, user, passwd);

    }

    public void closeConnection(Connection conn) throws SQLException {

        conn.close();

    }

}

默認(rèn)的構(gòu)造函數(shù)設(shè)置中,是讀取jdbc.properties文件中的設(shè)置,如果打算自行指定屬性文件名稱,則可以使用另一個有參數(shù)的構(gòu)造函數(shù)。Properties的getProperty()方法會讀取屬性文件中的“鍵(Key)”對應(yīng)的“值(Value)”,假設(shè)您的屬性文件設(shè)置如下:

Ü 范例20.3  jdbc.properties

onlyfun.caterpillar.driver=com.mysql.jdbc.Driver

onlyfun.caterpillar.url=jdbc:mysql://localhost:3306/demo

onlyfun.caterpillar.user=root

onlyfun.caterpillar.password=123456

DBSource的getConnection()方法簡單地從DriverManager的getConnection()方法獲得Connection對象,而closeConnection()方法則是將給定的Connection關(guān)閉。就簡單的連接程序來說,這樣已經(jīng)足夠,不過待會還會介紹連接池(Connection pool)的概念,到時將會修改一下DBSource的getConnection()和closeConnection()方法,以達到重復(fù)使用Connection、節(jié)省資源的目的。

最后,范例20.4使用一個簡單的程序來測試SimpleDBSource是否可以正確地獲得與數(shù)據(jù)庫的連接,以及是否正確地關(guān)閉連接。

Ü 范例20.4  ConnectionDemo.java

package onlyfun.caterpillar;

import java.io.IOException;

import java.sql.Connection;

import java.sql.SQLException;

public class ConnectionDemo {

    public static void main(String[] args) {

        try {

            DBSource dbsource = new SimpleDBSource();

            Connection conn = dbsource.getConnection();

           

            if(!conn.isClosed()) {

                System.out.println("數(shù)據(jù)庫連接已開啟…");

            }

           

            dbsource.closeConnection(conn);

           

            if(conn.isClosed()) {

                System.out.println("數(shù)據(jù)庫連接已關(guān)閉…");

            }

           

        } catch (IOException e) {

            e.printStackTrace();

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        } catch (SQLException e) {

            e.printStackTrace();

        }

    }

}

如果您的demo數(shù)據(jù)庫已建立,并正確設(shè)置jdbc.properties中的相關(guān)信息,則應(yīng)該能看到以下的執(zhí)行結(jié)果:

數(shù)據(jù)庫連接已開啟…

數(shù)據(jù)庫連接已關(guān)閉…

20.1.4 簡單的連接池(Connection pool)

在數(shù)據(jù)庫應(yīng)用程序中,數(shù)據(jù)庫連接的獲得是一個耗費時間與資源的操作,包括了建立Socket connection、交換數(shù)據(jù)(用戶密碼驗證、相關(guān)參數(shù))、會話(Session)、日志(Logging)、分配進程(Process)等資源。

如果數(shù)據(jù)庫的操作是很頻繁的動作,則要考慮到重復(fù)使用連接的需求,以節(jié)省在獲得連接時的時間與資源,通常會實現(xiàn)一個連接池(Connection pool),有需要連接時可以從池中獲得,不需要連接時就將連接放回池中,而不是直接關(guān)閉連接。

這里將實現(xiàn)一個簡單的連接池,示范連接池中,重復(fù)使用連接的基本概念,范例20.5使用java.util.ArrayList來實現(xiàn)連接池,可以將先前使用過的連接放到ArrayList對象中,下一次需要連接時則直接從ArrayList中獲得。

Ü 范例20.5  BasicDBSource.java

package onlyfun.caterpillar;

import java.io.FileInputStream;

import java.io.IOException;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.List;

import java.util.Properties;

public class BasicDBSource implements DBSource {

    private Properties props;

    private String url;

    private String user;

    private String passwd;

    private int max; // 連接池中最大Connection數(shù)目

    private List<Connection> connections;

    public BasicDBSource() throws IOException, ClassNotFoundException {

        this("jdbc.properties");

    }

   

    public BasicDBSource(String configFile) throws IOException,

                                                     ClassNotFoundException {

        props = new Properties();

        props.load(new FileInputStream(configFile));

       

        url = props.getProperty("onlyfun.caterpillar.url");

        user = props.getProperty("onlyfun.caterpillar.user");

        passwd = props.getProperty("onlyfun.caterpillar.password");

        max = Integer.parseInt(

                   props.getProperty("onlyfun.caterpillar.poolmax"));

        Class.forName(

                   props.getProperty("onlyfun.caterpillar.driver"));

       

        connections = new ArrayList<Connection>();

    }

    public synchronized Connection getConnection()

                                                    throws SQLException {

        if(connections.size() == 0) {

            return DriverManager.getConnection(url, user, passwd);

        }

        else {

            int lastIndex = connections.size() - 1;

            return connections.remove(lastIndex);

        }

    }

   

    public synchronized void closeConnection(Connection conn)

                                                        throws SQLException {

        if(connections.size() == max) {

            conn.close();

        }

        else {

            connections.add(conn);

        }

    }

}

BasicDBSource也實現(xiàn)DBSource接口,考慮這個類可能在多線程的環(huán)境中使用,因此在getConnection()與closeConnection()方法上使用syhchronized加以修飾。在獲得連接時,如果目前池中沒有Connection對象,則新建立一個連接,如果有存在的Connection對象,則從池中移出。

BasicDBSource可以設(shè)置連接池中最大Connection保存數(shù)量,如果超過這個數(shù)量,則傳入closeConnection()方法的Connection對象直接關(guān)閉,否則就放入連接池中,以在下一次需要數(shù)據(jù)庫連接時直接使用。范例20.6是個測試BasicDBSource的簡單程序。

Ü 范例20.6  ConnectionPoolDemo.java

package onlyfun.caterpillar;

import java.io.IOException;

import java.sql.Connection;

import java.sql.SQLException;

public class ConnectionPoolDemo {

    public static void main(String[] args) {

        try {

            DBSource dbsource = new BasicDBSource("jdbc2.properties");

            Connection conn1 = dbsource.getConnection();

            dbsource.closeConnection(conn1);

            Connection conn2 = dbsource.getConnection();

            System.out.println(conn1 == conn2);

           

        } catch (IOException e) {

            e.printStackTrace();

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        } catch (SQLException e) {

            e.printStackTrace();

        }

       

    }

}

這里所使用的設(shè)置文件是jdbc2.properties,當(dāng)中多了連接池最大數(shù)量之設(shè)置,如下所示:

Ü 范例20.7  jdbc2.properties

onlyfun.caterpillar.driver=com.mysql.jdbc.Driver

onlyfun.caterpillar.url=jdbc:mysql://localhost:3306/demo

onlyfun.caterpillar.user=root

onlyfun.caterpillar.password=123456

onlyfun.caterpillar.poolmax=10

程序中獲得Connection之后,將之使用closeConnection()方法關(guān)閉,但實際上closeConnection()方法并不是真正使用Connection的close()方法,而是放回池中,第二次獲得Connection時,所獲得的是先前放入池中的同一對象,因此執(zhí)行的結(jié)果會顯示true。

在更復(fù)雜的情況下,您還需要考慮到初始的Connection數(shù)量、Connection最大idle的數(shù)量、如果超過多久時間,要回收多少數(shù)量的Connection等問題。實際上也不需要自行設(shè)計連接池的程序,現(xiàn)在網(wǎng)絡(luò)上有不少優(yōu)秀的開放原始碼連接池程序,例如Proxool(http://proxool./index.html)或Apache Jakarta的Common DBCP(http://jakarta./commons/dbcp/),您可以自行參考官方網(wǎng)站上的相關(guān)文件,了解它們是如何設(shè)置與使用的。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多