更新時間:2020-01-15 來源:黑馬程序員 瀏覽量:
1、什么是JDBC?
在web開發(fā)中,不可避免的地要使用數(shù)據(jù)庫來存儲和管理數(shù)據(jù)。為了在java語言中提供數(shù)據(jù)庫訪問的支持,Sun公司于1996年提供了一套訪問數(shù)據(jù)的標準Java類庫,即JDBC。
JDBC的全稱是Java數(shù)據(jù)庫連接(Java Database connect),它是一套用于執(zhí)行SQL語句的Java API。應用程序可通過這套API連接到關系數(shù)據(jù)庫,并使用SQL語句來完成對數(shù)據(jù)庫中數(shù)據(jù)的查詢、更新和刪除等操作。應用程序使用JDBC訪問數(shù)據(jù)庫的方式如下圖所示。
從上圖可以看出,應用程序使用JDBC訪問特定的數(shù)據(jù)庫時,需要與不同的數(shù)據(jù)庫驅動進行連接。由于不同數(shù)據(jù)庫廠商提供的數(shù)據(jù)庫驅動不同,因此,為了使應用程序與數(shù)據(jù)庫真正建立連接,JDBC不僅需要提供訪問數(shù)據(jù)庫的API,還需要封裝與各種數(shù)據(jù)庫服務器通信的細節(jié)為了幫助大家更好地理解應用程序如何通過JDBC訪問數(shù)據(jù)庫,下面通過一張圖來描述JDBC的具體實現(xiàn)細節(jié),如下圖。
從上圖中可以看出,JDBC的實現(xiàn)包括三部分。
(1)JDBC驅動管理器:負責注冊特定的JDBC驅動器,主要通過java.sql. Driver Manager類實現(xiàn)。
(2)JDBC驅動器API:由Sun公司負責制定,其中最主要的接口是java.sql. Driver接口。
(3)JDBC驅動器:它是一種數(shù)據(jù)庫驅動,由數(shù)據(jù)庫廠商創(chuàng)建,也稱為JDBC驅動程序JDBC驅動器實現(xiàn)了JDBC驅動器API,負責與特定的數(shù)據(jù)庫連接,以及處理通信細節(jié)。
2、JDBC常用API
在開發(fā)JDBC程序前,首先了解一下JDBC常用的API。JDBC API主要位于java.sql包中,該包定義了一系列訪問數(shù)據(jù)庫的接口和類,具體如下。
1. Driver接口
Driver接口是所有JDBC驅動程序必須實現(xiàn)的接口,該接口專門提供給數(shù)據(jù)庫廠商使用。在編寫JDBC程序時,必須要把指定數(shù)據(jù)庫驅動程序或類庫加載到項目的classpath中。
2. DriverManager類
Driver Manager類用于加載JDBC驅動并且創(chuàng)建與數(shù)據(jù)庫的連接。在Driver Manager類中,定義了兩個比較重要的靜態(tài)方法。如表所示:
registerDriver(Driver driver)
該方法用于向 DriverManager中注冊給定的JDBC驅動程程序
getConnection(String url,String user,String pwd)
該方法用于建立和數(shù)據(jù)庫的連接,并返回表示連接的 Connection對象
3、Connection接口
Connection接口代表Java程序和數(shù)據(jù)庫的連接,在Connection接口中,定義了一系列方法,具體如表所示。
getMetaData()
該方法用于返回表示數(shù)據(jù)庫的元數(shù)據(jù)的 DatabaseMetaData對象
createStatement()
用于創(chuàng)建一個Statement對象來將SQL語句發(fā)送到數(shù)據(jù)庫
prepareStatement(String sql)
用于創(chuàng)建一個PreparedStatement對象來將參數(shù)化的SQL語句發(fā)送到數(shù)據(jù)庫
prepareCall(String sql)
用于創(chuàng)建一個CallableStatement對象來調(diào)用數(shù)據(jù)庫存儲過程
4、Statement接口
Statement接口用于向數(shù)據(jù)庫發(fā)送SQL語句,在Statement接口中,提供了三個執(zhí)行SQL語句的方法,具體如表所示。
execute(String sql)
用于執(zhí)行各種SQL語句,該方法返回一個boolean類型的值,如果為true,表示所執(zhí)行的SQL語句具備查詢結果,可通過Statement的getResultSet方法獲得查詢結果。
executeUpdate(String sql)
用于執(zhí)行SQL中的Insert、update和delete語句。該方法返回一個int類型的值,表示數(shù)據(jù)庫中受該SQL語句影響的記錄的數(shù)目。
executeQuery(String sql)
用于執(zhí)行SQL中的select語句,該方法返回一個表示查詢結果的ResultSet對象
5. PreparedStatement接口
PreparedStatement是Statement的子接口,用于執(zhí)行預編譯的SQL語句。在PreparedStatement接口中,提供了一些基本操作的方法,具體如表下所示。
executeUpdate()
在此PreparedStatement對象中執(zhí)行SQL語句,該語句必須是個DML語句或者是無返回內(nèi)容的SQL語句,比如DDL語句。
executeQuery()
在此PreparedStatement對象中執(zhí)行SQL查詢,該方法返回的ResultSet對象
setInt(int parameterIndex, int x)
將指定參數(shù)設置為給定的int值
setFloat(int parameterIndex, float x)
指定參數(shù)設置為給定的float值
setString(int parameterIndex, String x)
將指定參數(shù)設置為給定的String值
setDate(int parameterIndex, Date x)
將指定參數(shù)設置為給定的Date值
addBatch()
將一組參數(shù)添加到此PreparedStatement對象的批處理命令中
setCharacterStream(parameterIndex, reader, length)
將指定的輸入流寫入數(shù)據(jù)庫的文本字段
setBinaryStream(parameterIndex, x, length)
將二進制的輸入流數(shù)據(jù)寫入到二進制字段中
需要注意的是,上表中的setDate()方法可以設置日期內(nèi)容,但參數(shù)Date的類型是java.sq.Date,而不是java.util.Date。
6、CallableStatement接口
CallableStatement是PreparedStatement的子接口,用于執(zhí)行SQL存儲過程。在Callablestatement按接口中,提供了一些基本操作的方法,具體下表所示:
registerOutParameter(int parameterIndex,int sqlType)
按順序位置將OUT參數(shù)注冊為SQL類型。其中,parameterIndex表示順序位置,sqlType表示SQL類型
setNull(String parameter Name, int sqlType)
將指定參數(shù)設置為SQL類型的NULL
setString(String parameterName, String x)
查詢最后一個讀取的OUT參數(shù)是否為SQL類型的NULL
wasNull()
查詢最后一個讀取的OUT參數(shù)是否為SQL類型的NULL
getlnt(int parameterIndex)
以Java語言中int值的形式獲取指定的數(shù)據(jù)庫中INTEGER類型參數(shù)的值
需要注意的是,由于 CallableStatement接口繼承PreparedStatement,PreparedStatement接口又繼承了 Statement,因此CallableStatement接口中除了擁有自己特有的方法,也同時擁有了這兩個父接口中的方法。
7、ResultSet接口
ResultSet接口表示 select查詢語句得到的結果集,該結果集封裝在一個邏輯表格中。在 ResultSet接口內(nèi)部有一個指向表格數(shù)據(jù)行的游標,ResultSet對象初始化時,游標在表格的第一行之前。下表中列舉了ResultSet接口中的常用方法。
getString(int columnIndex)
用于獲取指定字段的String類型的值,參數(shù)columnIndex代表字段的索引
getString(String columnName)
用于獲取指定字段的String類型的值,參數(shù)column Name代表字段的名稱
getInt(int columnIndex)
用于獲取指定字段的int類型的值,參數(shù)columnIndex代表字段的索引
getInt(String columnName)
用于獲取指定字段的int類型的值,參數(shù)columnName代表字段的名稱
getDate(int columnIndex)
用于獲取指定字段的Date類型的值,參數(shù)columnIndex代表字段的索引
getDate(String columnName)
用于獲取指定字段的Date類型的值,參數(shù)column Name代表字段的名稱
next()
將游標從當前位置向下移一行
absolute(int row)
將游標移動到此Resultset對象的指定行
afterLast()
將游標移動到此ResultSet對象的末尾,即最后一行之后
beforeFirst()
將游標移動到此Resultset對象的開頭,即第一行之前
previous()
將游標移動到此ResultSet對象的上一行
last()
將游標移動到此ResultSet對象的最
從上表中可以看出,ResultSet接口中定義了大量的getXxx()方法,采用哪種getXxx()方法取決于字段的數(shù)據(jù)類型。程序既可以通過字段的名稱來獲取指定數(shù)據(jù),也可以通過字段的索引來獲取指定的數(shù)據(jù),字段的索引是從1開始編號的。
3、實現(xiàn)第一個JDBC程序
通過前面的學習,我們對JDBC及其常用API有了大致的了解,接下來就開始介紹JDBC編程,JDBC編程大致按照以下幾個步驟進行。
(1) 加載并注冊數(shù)據(jù)庫驅動,具體方式如下。
DriverManager.registerDriver(Driver driver);
(2) 通過Driver Manager獲取數(shù)據(jù)庫連接,具體方式如下。
Connection conn= DriverManager.getConnection(String url, String user, String pass);
從上述方式可以看出,getConnection()方法中有三個參數(shù),它們分別表示數(shù)據(jù)庫url、登錄數(shù)據(jù)庫的用戶名和密碼。數(shù)據(jù)庫山通常遵循如下形式的寫法。
jdbc:subprotocol:subname
上面的URL寫法中jdbc部分是固定的,subprotocol指定鏈接達到特定數(shù)據(jù)庫的驅動程序,而subname部分則很不固定,也沒有什么規(guī)律,不同數(shù)據(jù)庫的形式可能存在較大差異,一Mysql數(shù)據(jù)庫為例,其形式如下:
jdbc:mysql://hostname:port/databasename
(3)通過Connection對象獲取Statement對象。Connection創(chuàng)建Statement的方式有如下三種。
① createStatement(): 創(chuàng)建基本的Statement對象
② prepareStatement(): 創(chuàng)建PreparedStatement對象。
③ preparCall(): 創(chuàng)建CallableStatement對象。
以創(chuàng)建基本的Statement對象為例,具體方式如下。
Statement stmt=conn.createStatement();
(4)使用Statement執(zhí)行SQL語句。所有的Statement都有如下三種方法來執(zhí)行語句。
①execute():可以執(zhí)行任何SQL語句。
②executeQuery():通常執(zhí)行查詢語句,執(zhí)行后返回代表結果集的Resultset對象。
③executeUpdate():主要用于執(zhí)行DML和DDL語句。執(zhí)行DML語句,如INSERT、UPDATE或 DELETE時,返回受SQL語句影響的行數(shù),執(zhí)行DDL語句返回0。
以executeQuer()方法為例,具體方式如下。
//執(zhí)行SQL語句,獲取結果集ResulSet
ResultSet rs=stmt.executQuery(sql);
(5)操作ResultSet結果集。如果執(zhí)行的SQL語句是查詢語句,執(zhí)行結果將返回Resultset對象,該對象里保存了SQL語句查詢的結果。程序可以通過操作該ResultSet對象來取出查詢結果。 ResultSet對象提供的方法主要可以分為以下兩類。
①next()、previous()、first()、last()、beforeFirst()、afterLast()、absolute()等移動記錄指針的方法
②getXxx()獲取指針指向行,特定列的值。
(6)回收數(shù)據(jù)庫資源。關閉數(shù)據(jù)庫連接,釋放資源,包括關閉ResultSet、Statement和Connection等資源。
至此,JDBC編程的大致步驟已經(jīng)完成,為了幫助讀者快速學習如何開發(fā)JDBC程序,接下來,編寫第一個JDBC程序,改程序從user表中讀取數(shù)據(jù),并將結果結果打印在控制臺,具體步驟入戲所示。
1、搭建實驗環(huán)境
CREATE DATABASE chapter01;
USE chapter01;
CREATE TABLE users(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(40),
password VARCHAR(40),
email VARCHAR(60),
birthday DATE
)CHARACTER SET utf8 COOLLATE utf8_genneral_ci;
數(shù)據(jù)庫和表創(chuàng)建成功后,再向users表中插入三條數(shù)據(jù),SQL語句如下所示。
INSERT INTO users(NAME,PASSWORD,email,birthday)
VALUES('zs','123456','zs@sina.com','1980-12-04');
INSERT INTO users(NAME,PASSWORD,email,birthday)
VALUES('lisi',123456,1isi@sina.com,'1981-12-04');
INSERT INTO users(NAME,PASSWORD,email,birthday)
VALUES('wangwu',123456,'wangwu@sina.com','1979-12-04');
2、導入數(shù)據(jù)庫驅動
新建Java工程chapter01,將要訪問的數(shù)據(jù)庫驅動文件添加到classpath中。由于應用程序訪問的是MySQL數(shù)據(jù)庫,因此,將MySQL的數(shù)據(jù)庫驅動文件mysql-connector-java-5.0.8-bin.jar添加到classpath中即可。
3、編寫JDBC程序
在工程chapter01中,新建Java類Example01,該類用于讀取數(shù)據(jù)庫中的users表,并將結果輸出,如例下面案例所示。
package cn.itcast.jdbc.example;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Date;
public class Example01 {
public static void main(String[] args) throws SQLException {
//1.注冊數(shù)據(jù)庫的驅動
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2.通過 DriverManager獲取數(shù)據(jù)庫連接
String url="jdbc:mysql://localhost:3306/chapter01";
String usernames="root";
String password="itcast";
Connection conn=DriverManager.getConnection(url, username, password);
//3.通過 Connection對象獲取 Statement對象
Statement stmt= conn.createStatement();
//4.使用 Statement執(zhí)行SQL語句
String sql="select * from users";
ResultSet rs=stmt.executeQuery(sql);
//5、操作 ResultSet結果集
System.out.println("id|name|password|email|birthday");
while (rs.next()) {
int id=rs.getInt("id"); //通過列名獲取指定字段的值
String name=rs.getString("name");
String psw=rs.getString("password");
String email=rs.getString("email");
Date birthday=rs.getDate("birthday");
System.out.println(id+"|"+name+"|"+psw+"|"+email+"|"+birthday);
}
//6.回收數(shù)據(jù)庫
rs.close();
stmt.close();
conn.close();
}
}
程序執(zhí)行后,會講從users表中讀取到的數(shù)據(jù)打印到控制臺。
在上面案例中演示了JDBC訪問數(shù)據(jù)庫的步驟。首先注冊MySQL的數(shù)據(jù)庫驅動器類,通過 DriverManager獲取一個Connection對象,然后使用Connection對象創(chuàng)建了一個Statement對象,Statement對象能夠通過executeQuery()方法執(zhí)行SQL語句,并返回結果集ResultSet對象。最后,通過遍歷Resultset對象便可得到最終的查詢結果需要注意的是,在實現(xiàn)第一個JDBC程序時,還有兩個方面需要改進,具體如下。
1、注冊驅動
在注冊數(shù)據(jù)庫驅動時,雖然DriverManager.registerDriver(new com. mysql.jdbc.Driver())方法可以完成,但會使數(shù)據(jù)庫驅動被注冊兩次。這是因為Driver類的源碼中,已經(jīng)在靜態(tài)代碼塊中完成了數(shù)據(jù)庫驅動的注冊。所以,為了避免數(shù)據(jù)庫驅動被重復注冊,只需要在程序中加載驅動類即可,具體加載方式如下所示。
Class.forName("com.mysqk.jdbc.Driver");
2、釋放資源
由于數(shù)據(jù)庫資源非常寶貴,數(shù)據(jù)庫允許的并發(fā)訪問連接數(shù)量有限,因此,當數(shù)據(jù)庫資源使用完畢后,一定要記得釋放資源。為了保證資源的釋放,在Java程序中,應該將最終必須要執(zhí)行的操作放在finally代碼塊中,具體方式如下。
if(rs!=null) {
try {
rs.close();
}catch (SQLException e) {
e.printStackTrace();
}
rs=null;
}
if(stmt!=null) {
try {
stmt.close();
}catch (SQLException e) {
e.printStackTrace();
}
stmt=null;
}
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn=null;
}