JDBC(Java data Base Connectivity)是Java語言為了支持SQL功能而提供的與數據庫相聯的用戶接口,JDBC中包括了一組由Java語言書寫的接口和類,它們都是獨立于特定的DBMS,或者說它們可以和各種數據相關聯。有了JDBC以后,程序員可以方便地在Java語言中使用SQL語言,從而使Java應用程序或Java applet可以實現對分布在網絡上的各種關系數據庫的訪問。使用了JDBC以后,程序員可以將精力集中于上層的功能實現,而不必關心底層與具體的DBMS的連接和訪問過程。
11.1
關系數據庫簡介
關系數據庫系統的思想是由IBM公司的E.F.Codd于1970年率先提出的。
關系數據庫支持的數據模型是關系模型。關系模型的基本條件是其關系模式中每個屬性值必須是一個不可分割的數據量。簡單地說,在關系數據庫中數據結構一般是張兩維表,這張兩維表的每一列的值必須是不可分割的數據項,而任兩行應互不相同。
關系模型的主要特點是:
⑴結構簡單,表示力強,易于掌握。
⑵語言一體化,非過程化的操作,方便用戶使用。
⑶有一定的數學理論作基礎,利于進一步研究和發展。
⑷操作耗時,執行效率低。
關系數據庫管理系統一般向用戶提供數據檢索、數據插入、數據刪除、數據修改四種基本操作功能
。
11.2JDBC
概述
JDBC由一組Java語言編寫的類和接口組成,使用內嵌式的SQL,主要實現三方面的功能:建立與數據庫的連接,執行SQL聲明以及處理SQL執行結果。JDBC支持基本的SQL功能,使用它可方便地與不同的關系型數據庫建立連接,進行相關操作,并無需再為不同的DBMS分別編寫程序。下面我們先介紹JDBC與SQL及ODBC的關系,再介紹JDBC支持的兩種模型,最后介紹JDBC的抽象接口和數據庫驅動器Driver。
11.2.1 JDBC與SQL
盡管一般數據庫系統在很大范圍內支持SQL的語義語法,但它們在復雜的高層次功能如存儲功能調用和外部連接等方面往往不盡一致。為了解決這一矛盾,JDBC采用以下的幾種措施:
(1)JDBC允許使用從屬于DBMS的系統的任何詢問語句,這些詢問語句都將被傳送給后臺的DBMS實際執行。這樣增加了使用的靈活性,一個應用程序的詢問可以不是SQL形式的,而是SQL的特定引出形式,如為特定的DBMS提供的文件或圖片查詢。這樣做的風險則在某些DBMS中可以會出現錯誤。
(2)一般認為ANSI SQL Entry Level的功能比較完備,而且是被廣泛支持的。因此為了使JDBC與SQL一致,要求用戶使用至少ANSI SQL 92 Entry Level以上的版本,這樣就給那些要求廣泛的可攜帶性的應用程序提供了共同命名的保證。
(3)對較復雜的應用,JDBC提供了接口類DatabaseMetadata,用戶可通過這個類獲取相應DBMS的描述信息,再根據所得信息采取特定的查詢操作方式。
11.2.2 JDBC與ODBC
Microsoft的ODBC(Open DataBase Connectivity)是當前與關系型數據庫連接最常用的接口。JDBC是建立在ODBC的基礎上的,實際上可視為ODBD的Java語言翻譯形式。當然兩者都是建立在X/Open SQL CLI(Call Level Interface)的抽象定義之上的。而JDBC與ODBC相比,在使用上更為方便。
既然ODBC已經是成型的通用接口,我們可在Java程序中直接使用ODBC卻要建立JDBC接口,這樣做的原因和好處包括以下幾點:
(1)ODBC使用的是C語言界面,而從Java直接調用C源碼容易在安全性、健壯性和可移植性等方面產生問題,運行功效也受到影響。
(2)將ODBC的C語言API逐字譯為Java也并不理想。比如,Java沒有指針,ODBC的一種面向對象式的翻譯界面,對Java的程序員來說更為自然方便。
(3)ODBC難于學習掌握,經常將簡單的特性與復雜的特性混合使用。而JDBC相對簡單明了許多,容易理解掌握。
(4)JDBC有助于實現“純Java“的方案。當使用ODBC時,每一臺客戶機都要求裝入ODBC的驅動器和管理器。而當使用JDBC,驅動器完全由Java語言編寫時,JDBC代碼可以在所有的Java平臺上自動裝入、移植,而且是安全的。
當然,在JDBC也可以使用ODBC,但是要通過中介JDBC-ODBC Bridge使用。
11.2.3 JDBC支持的兩種模型
在與數據庫的連接操作中,JDBC支持兩種不同的模型。這兩川模型根據用戶與數據庫的關系層次不同,分別稱為兩模型和三層模型。
兩層模型中,Java的應用程序(Applet或Application)直接與數據庫聯系。用戶的SQL聲明被提交給數據庫,執行的結果回送給用戶,如下圖所示。這種模型具有客戶機/服務器結構,用戶的機器如同客戶機,存放數據庫的機器則如同服務器,連接兩者的可以是局域網,也可以是廣域網。
┌─────────┐
│Java Application │
│ Java Applet │ Clinet Machine
├─────────┤
│ JDBC │
└─────────┘
↑
↓
┌─────────┐
│ DBMS │ Database Serve
└─────────┘
圖11.1 JDBC支持的兩層模型
│Java Application │
│ Java Applet │ Clinet Machine
├─────────┤
│ JDBC │
└─────────┘
↑
↓
┌─────────┐
│ DBMS │ Database Serve
└─────────┘
圖11.1 JDBC支持的兩層模型
在三層模型中,用戶不直接與數據庫聯系。用戶的命令首先發送給一個所謂“中間層”,中間層再將SQL聲明發給DMBS。執行的結果也同樣由中間層轉交,如圖11.2所示。三層模型的好處是,可以通過中間層保持對存取權限和公有數據允許修改類型的控制,便于安全管理。同時,用戶可以使用一種較為友善的高層API,由中間層轉化為恰當的低層命令,保證較好地運行功效。到目前為止,中間層多用C或C++語言編寫。隨著Java語言的逐步推廣,將出現用Java編寫的中間層,更好地利用它的健壯性、多線程,安全性等特點。
┌──────────┐
│ Java Applet │
│ HTML Browse │
└──────────┘
↑
↓
┌──────────┐
│Application Server │
│ (Java) │
├──────────┤
│ JDBC │
└──────────┘
↑
↓
┌──────────┐
│ DBMS │
└──────────┘
圖11.2 JDBC支持的三層模型
│ Java Applet │
│ HTML Browse │
└──────────┘
↑
↓
┌──────────┐
│Application Server │
│ (Java) │
├──────────┤
│ JDBC │
└──────────┘
↑
↓
┌──────────┐
│ DBMS │
└──────────┘
圖11.2 JDBC支持的三層模型
11.2.4 JDBC的抽象接口
JDBC中最重要的部分是定義了一系列的抽象接口,通過這些接口,JDBC實現了三個基本的功能:建立與數據的連接、執行SQL聲明和處理執行結果。
這些接口都存在Java的sql包中,它們的名稱和基本功能是:
*java.sql.DriverMagnager
管理驅動器,支持驅動器與數據連接的創建。
*java.sql.Connection
代表與某一數據庫的連接,支持SQL聲明的創建。
*java.sql.Statement
在連接中執行一靜態的SQL聲明并取得執行結果。
*java.sql.PreparedStatement
Statement的子類,代表預編譯的SQL聲明。
*java.sql.CallableStatement
Statement的子類,代表SQL的存儲過程。
java.sql.ResultSet
代表執行SQL聲明后產生的數據結果。
11.2.5 JDBC的數據庫驅動器Driver
Java的應用程序員通過sql包中定義的一系列抽象類對數據庫進行操作,而實現這些抽象類,實際完成操作,則是由數據庫驅動器Driver運行的。它們之間的層次關系如圖11.3所示
┌─────────┐
│Java Application │
└─────────┘
JDBC API ————————
┌─────────┐
│JDBC Manager │
└─────────┘
——————————————
┌─────┐┌───-─--─┐┌─────┐┌───────-┐
DJBC │JDBC-Net││JDBC-ODBC | │Native-API││Native-Protocol |
│Java Application │
└─────────┘
JDBC API ————————
┌─────────┐
│JDBC Manager │
└─────────┘
——————————————
┌─────┐┌───-─--─┐┌─────┐┌───────-┐
DJBC │JDBC-Net││JDBC-ODBC | │Native-API││Native-Protocol |
Drivers│ Driver ││Bridge Driver││Driver │ |Driver |
└─────┘└───-──--┘└─────┘└─────-──┘
↓ ↓ ↓ ↓
┌───────────────────────────────────┐
│ D B M S |
───────────────────────────────────-┘
圖11.3 JDBC Drivers
└─────┘└───-──--┘└─────┘└─────-──┘
↓ ↓ ↓ ↓
┌───────────────────────────────────┐
│ D B M S |
───────────────────────────────────-┘
圖11.3 JDBC Drivers
JDBC的Driver可分為以下四種類型:
(1)JDBC-ODBC Bridge和ODBC Driver
這種驅動器器通過ODBC驅動器提供數據庫連接。使用這種驅動器,要求每一臺客戶機都裝入ODBC的驅動器。
(2)Native-API partly-Java Driver
這種驅動器將JDBC指令轉化成所連接使用的DBMS的操作形式。各客戶機使用的數據庫可能是Oracle,可能是Sybase,也可能是Access,都需要在客戶機上裝有相應DBMS的驅動程序。
(3)JDBC-Net All-Java Driver
這種驅動器將JDBC指令轉化成獨立于DBMS的網絡協議形式,再由服務器轉化為特定DBMS的協議形式。有關DBMS的協議由各數據庫廠商決定。這種驅動器可以聯接到不同的數據庫上,最為靈活。目前一些廠商已經開始添加JDBC的這種驅動器到他們已有的數據庫中介產品中。要注意的是,為了支持廣域網存取,需要增加有關安全性的措施,如防火墻等等。
(4)Native-protocol All-Java Driver
這種驅動器將JDBC指令轉化成網絡協議后不再轉換,由DBMS直接使用。相當于客戶機直接與服務器聯系,對局域網適用。
在這四種驅動器中,后兩類“純Java”(All-Java)的驅動器效率更高,也更具有通用性。但目前第一、第二類驅動器比較容易獲得,使用也較普遍。
16.3 JDBC
編程
11.3.1 程序基本結構
一般的
JDBC程序都完成三項功能:
與數據庫建立連接;傳送SQL 聲明以及對返回結果進行處理
。下面我們通過一個具體例子說明這三項功能的實現過程。
例11.1 Creage.java給出了一個簡單的JDBC程序,此程序執行后創建一張名為testTable的表,表中包括兩個域,域名分別為id和name。
1: import java.net.URL;
2: import java.sql.*;
3:
4: class Create{
5: public static void main (String[] args){
6: String url="jdbc:odbc:demo";
7: String query="CREATE TABLE testTable" + "(id INT,name CHAR(10))";
8:
9: try{
10: //下載jdbc-odbc bridge 驅動器
11: Class.forName (" sun.jdbc.odbc.JdbcOdbcDriver ");//關于此句參見下面Cyclone的注釋
//與驅動器建立連接 ,這里可使用不同的特定驅動,如jdbcfororacle或jdbcforsqlserver
14: Connection con=DriverManager.getConnection (url,"user","password");
15:
16: //創建一個Statement對象
17: Statement stmt=con.createStatement();
18:
19: //執行SQL聲明
20: stmt.executeUpdate(query);
21: System.out.println("Create successfully!");
22:
23: //關閉 stm
24: stmt.close();
25:
26: //關閉連接
27: con.close();
28: }catch(SQLException ex){
//SQL異常信息
29:System.out.println("\n***SQLException caught ***\n");
30: while(ex!=null){
31: System.out.println("SQLState:"+ex.getSQLState());
32: System.out.println("Message:"+ex.getMessage());
33: System.out.println("Vendor:"+ex.getErrorCode());
34: ex=ex.getNextException();
35: System.out.println("");
}
36:}catch(java.lang.Exception ex){
37:ex.printStackTrace();
38:}
39:}
40:}
2: import java.sql.*;
3:
4: class Create{
5: public static void main (String[] args){
6: String url="jdbc:odbc:demo";
7: String query="CREATE TABLE testTable" + "(id INT,name CHAR(10))";
8:
9: try{
10: //下載jdbc-odbc bridge 驅動器
11: Class.forName (" sun.jdbc.odbc.JdbcOdbcDriver ");//關于此句參見下面Cyclone的注釋
//與驅動器建立連接 ,這里可使用不同的特定驅動,如jdbcfororacle或jdbcforsqlserver
14: Connection con=DriverManager.getConnection (url,"user","password");
15:
16: //創建一個Statement對象
17: Statement stmt=con.createStatement();
18:
19: //執行SQL聲明
20: stmt.executeUpdate(query);
21: System.out.println("Create successfully!");
22:
23: //關閉 stm
24: stmt.close();
25:
26: //關閉連接
27: con.close();
28: }catch(SQLException ex){
//SQL異常信息
29:System.out.println("\n***SQLException caught ***\n");
30: while(ex!=null){
31: System.out.println("SQLState:"+ex.getSQLState());
32: System.out.println("Message:"+ex.getMessage());
33: System.out.println("Vendor:"+ex.getErrorCode());
34: ex=ex.getNextException();
35: System.out.println("");
}
36:}catch(java.lang.Exception ex){
37:ex.printStackTrace();
38:}
39:}
40:}
11.3.2 Statement類及其子類
1)Statement接口
Statement stmt=con.createStatement();
//執行SQL聲明
int count1=stmt.executeUpdate("INSERT INTO testTable(id,name) VALUES(1,'wu')");
int count2=stmt.executeUpdate("INSERT INTO testTable(id,name) VALUES(2,'wang')");
//執行SQL聲明
int count1=stmt.executeUpdate("INSERT INTO testTable(id,name) VALUES(1,'wu')");
int count2=stmt.executeUpdate("INSERT INTO testTable(id,name) VALUES(2,'wang')");
2)
PreparedStatement接口
String data[][]={{"5","xu"},{"6","yan"}};
PreparedStatement pstmt=con.prepareStatement("INSERT INTO testTable (id,name) VALUES(?,?)");
//參數賦值,執行SQL聲明
for (int i=0;i<data.length;i++){
pstmt.setInt(1,Integer.parseInt(data[i][0]));
pstmt.setString(2,data[i][1]);
pstmt.executeUpdate();
}
//參數賦值,執行SQL聲明
for (int i=0;i<data.length;i++){
pstmt.setInt(1,Integer.parseInt(data[i][0]));
pstmt.setString(2,data[i][1]);
pstmt.executeUpdate();
}
3)
CallableStatement接口
CallableStatement cstmt=con.prepareCall("{call Search(?)}");
//參數賦值
cstmt.setInt(1,934678);
//執行儲存過程。
cstmt.execute();
//參數賦值
cstmt.setInt(1,934678);
//執行儲存過程。
cstmt.execute();
11.3.3 結果集ResultSet及ResultSetMetaData
String query = "SELECT * FROM testTable";
Statement stmt=con.createStatement();
//發出查詢要求,獲得結果集
ResultSet rs=stmt.executeQuery(query);
//顯示結果集各行各列
System.out.println("The detail of testTable is:");
ResultSetMetaData rsmd=rs.getMetaData();
//獲得結果集列數
in numCols=rsmd.getColumnCount();
//顯示列標題
for(int i=1;i<=numCols;i++)
{
if(i>1) System.out.print(",");
System.out.print (rsmd.getColumnLabel(i)) ;
}
System.out.println("");
//顯示結果集信息
while( rs.next() )
{
//顯示一行
for(int i=1;i<=numCols;i++)
{
if(i>1) System.out.print(",");
System.out.print( rs.getString(i) );
}
//發出查詢要求,獲得結果集
ResultSet rs=stmt.executeQuery(query);
//顯示結果集各行各列
System.out.println("The detail of testTable is:");
ResultSetMetaData rsmd=rs.getMetaData();
//獲得結果集列數
in numCols=rsmd.getColumnCount();
//顯示列標題
for(int i=1;i<=numCols;i++)
{
if(i>1) System.out.print(",");
System.out.print (rsmd.getColumnLabel(i)) ;
}
System.out.println("");
//顯示結果集信息
while( rs.next() )
{
//顯示一行
for(int i=1;i<=numCols;i++)
{
if(i>1) System.out.print(",");
System.out.print( rs.getString(i) );
}
11.3.4 DatabaseMetaData
DatabaseMetaData dma = con.getMetaData();
//驅動器和URL信息
System.out.println("\nConnected to" + dma.getURL());
System.out.println("Driver" + dma.getDriverName());
System.out.println("Version" + dma.getDriverVersion());
//數據庫信息
System.out.println("\nDataBase name:" + dma.getDatabaseProductName()+dma.getDatabaseProductVersion());
System.out.println("DataBase supports SQL keywords:\n\t" + dma.getSQLKeywords());
//數據庫功能信息函數
//驅動器和URL信息
System.out.println("\nConnected to" + dma.getURL());
System.out.println("Driver" + dma.getDriverName());
System.out.println("Version" + dma.getDriverVersion());
//數據庫信息
System.out.println("\nDataBase name:" + dma.getDatabaseProductName()+dma.getDatabaseProductVersion());
System.out.println("DataBase supports SQL keywords:\n\t" + dma.getSQLKeywords());
//數據庫功能信息函數
dma.supportsANSI92EntryLevelSQL()
dma.supportsANSI92FullSQL()
dma.supportsStoredProcedures()
11.3.5 JDBC數據類型及類型轉換
11.3.5 JDBC數據類型及類型轉換
一、JDBC的數據類型
JDBC的sql包中除了與數據庫連接有關的抽象接口及與驅動器有關的DriverManager、DriverPropertyInfo等類型外,還定義了若干數據類,用以代表數據庫中可能用到的SQL類型。下面我們就對它們逐一進行簡略介紹。
1、sql.Date
sql包中的日期類Date是util包中Date類的子類,實際上也是util.Date類的子集。它只處理年月日,而忽略小時和分秒,用以代表SQL的DATE信息。
Date類的構造方法為:
public Date(int year, int mouth, int day)
其中參數格式同util.Date類的構造方法一樣,年參數為所需設定的年份減去1900所得的整數值,月參數為0至11,日參數為1至31。如1998年1月23日所對應創建日期類的方法調用為:
Date d=new Date(98,0,23);
Date類還提供兩個與String類互相轉換的方法,分別是:
public static Date valueOf(String s)
將字符串類參數轉換為日期類對象。其中String類參數S的格式為“年-月-日”,加“1997-04-12”。
public String toString()
將日期類對象轉換為String類對象表示,同樣采用“年-月-日”的格式。
2、sql.Time
該類是util.Date類的子類,也是它的一個子集。在Time類里,只處理小時和分秒,代表SQL的TIME類型。它與sql.Date合起來才表示完整的util.Date類信息。
Time類的構造方法為:
public Time(int hour,int minute,int second)
其中小時參數值為0至23,分秒參數取值均為0至59。
與sql.Date一樣,Time類也定義了兩個與String類互相轉換的函數ValueOf和String。不同的是String類對象的格式為“小時:分:秒”,如“12:26:06”。
3、sql.Timestamp
這個類也是util.Date類的子類,其中除了包含年月日、小時和分秒和信息之外,還加入了納秒信息(nanosecond),1納秒即1毫微秒。Timestamp類用來代表SQL時間戳(Timestamp)類型信息。
Timestamp類的構造方法為:
public Timestamp(int year, int mouth, int date, int hour, int minute, int second, int nano)其中納秒參數的取值從0至999,999,999,其余各參數同前。
Timestamp類特別定義了設置和獲得納秒信息的方法,分別是
public getnanos()
獲取時間戳的納秒部分
public void setNanos(int n)
以給定數值設置時間戳的納秒部分
4、sql.Types
Types類是Object類的直接子類。在這個類中以靜態常量的形式定義了可使用的SQL的數值類型。所有這些類型常量都以前綴
public final static int
的形式標明是公有靜態整數,且不可改動。具體的類型名和含義如表11.1所示。其中OTHER用來代表數據庫定義的特殊數據,可以用getObject或setObject方法將其映射為一個Java的Object對象。
表11.1 Types中定義的SQL類型
類型名
|
含義
|
BIGINT
|
長整型數
|
BINARY
|
二進制數
|
BIT
|
比特數
|
CHAR
|
字符型
|
DATE
|
日期型
|
DECIMAL
|
十進制數
|
DOUBLE
|
雙精度數
|
FLOAT
|
浮點數
|
INTEGER
|
整數
|
LONGVARBINARY
|
可變長型二進制數
|
LONGVARCHAR
|
可變長型字符
|
NULL
|
空類型
|
NUMERIC
|
數值型
|
OTHER
|
其他類型
|
REAL
|
實數
|
SMALLINT
|
短整型
|
TIME
|
時間類型
|
TIMESTAMP
|
時間戳類型
|
TINYINT
|
微整型
|
VARBINARY
|
可變二進制數
|
VARCHAR
|
可變字符型
|
二、SQL與Java
由于SQL數據類型與Java的數據類型不一致,因而在使用Java類型的應用程序與使用SQL類型的數據庫之間,需要某種讀寫類型轉換機制。實際上我們前面介紹的ResultSet類的“get”系列方法,Statement及其子類的“set“系列方法和registerOutParameter方法,都是這一轉換機制的組成部分。
需要進行的讀寫轉換包括三種情況:
第一種情況是從數據庫中讀取數值后,存放在ResultSet對象中的是SQL類型的數據。而調用“get”系列方法時,JDBC才將SQL類型轉換為指定的Java類型
。在一般情形下,SQL類型相對應的Java類型如表11-2所示。
表11.2 SQL類型一般所對應的Java類型
SQL type
|
Java type
|
CHAR
|
java.lang.String
|
VARCHAR
|
java.lang.String
|
LONGVARCHAR
|
java.lang.String
|
NUMERIC
|
java.lang.Bignum
|
DECIMAL
|
java.lang.Bignum
|
BIT
|
boolean
|
TINYINT
|
byte
|
SMALLINT
|
short
|
INTEGER
|
int
|
BIGINT
|
long
|
REAL
|
float
|
FLOAT
|
double
|
DOUBLE
|
double
|
BINARY
|
byte[]
|
VARBINARY
|
byte[]
|
LONGVARBINARY
|
byte[]
|
DATE
|
java.sql.Date
|
TIME
|
java.sql.Time
|
TIMESTAMP
|
java.sql.Timestamp
|
當然,在使用時用戶可以指定將SQL類型轉換為某個需要的特定類型而不遵循表11.2。例如在結果集中的某個FLOAT型數值,依標準轉換應用使用getDouble方法獲取,但實際上按用戶的不同需求也可以使用getFloat,getInt,甚至gefByte方法獲取,但只是有可能影響數值精確度。表11.3列出了對每一SQL類型可用以獲取“get”方法的清單,其中“+”表示可以使用該方法,“*”表示最好使用該方法。
表11.3 獲取SQL類型使用的“get”方法
\
\ SQL \ 類型名 \ \ \ \ \ get \ 方法名 \ \ \ \ |
T
I N Y I N T |
S
M A L L I N T |
I
N T E G E R |
B
I G I N T |
R
E A L |
F
L O A T |
D
O U B L E |
D
E C I M A L |
N
U M E R I C |
B
I T |
C
H A R |
V
A R C H A R |
L
O N G V A R C H A R |
B
I N A R Y |
V
A R B I N A R Y |
L
O N G V A R B I N A R Y |
D
A T E |
T
I M E |
border-right: #d4d0c8; padding-right: 0.75pt; border-top: #d4d0c8; padding-left: 0.75pt; padding-bottom: 0.75pt; borde
發表評論
最新評論
|
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

評論