導(dǎo)語(yǔ):
最近一直在忙著自己的一個(gè)小項(xiàng)目,沒(méi)來(lái)得及寫(xiě)點(diǎn)東西,很是慚愧。本人也是接觸 Java
沒(méi)多久喳魏,也看過(guò)很多關(guān)于 JDBC 的文章,而本人希望以一個(gè)初學(xué)者的角度通過(guò)本篇文章把其他關(guān)于 JDBC 文章中精華的部分提取出來(lái)怀薛,并加上自己的理解來(lái)談一談 JDBC刺彩,并盡量做到淺顯易懂,希望能對(duì)各位有所幫助。
JDBC 是什么
JDBC 代表 Java 數(shù)據(jù)庫(kù)連接(Java Database Connectivity)创倔,它是用于Java編程語(yǔ)言和數(shù)據(jù)庫(kù)之間的數(shù)據(jù)庫(kù)無(wú)關(guān)連接的標(biāo)準(zhǔn) Java API嗡害,換句話說(shuō):JDBC 是用于在 Java 語(yǔ)言編程中與數(shù)據(jù)庫(kù)連接的 API。
JDBC API 支持用于數(shù)據(jù)庫(kù)訪問(wèn)的兩層和三層處理模型畦攘,但通常霸妹,JDBC 體系結(jié)構(gòu)由兩層組成:
- JDBC API:提供應(yīng)用程序到 JDBC 管理器連接。
- JDBC 驅(qū)動(dòng)程序 API:支持 JDBC 管理器到驅(qū)動(dòng)程序連接知押。
JDBC API 使用驅(qū)動(dòng)程序管理器(JDBC Driver Manager)并指定數(shù)據(jù)庫(kù)的驅(qū)動(dòng)程序來(lái)提供與數(shù)據(jù)庫(kù)的連接叹螟。
JDBC 驅(qū)動(dòng)程序管理器(JDBC Driver Manager)確保使用正確的驅(qū)動(dòng)程序來(lái)訪問(wèn)每個(gè)數(shù)據(jù)源。 驅(qū)動(dòng)程序管理器(JDBC Driver Manager)能夠支持連接到多個(gè)數(shù)據(jù)庫(kù)的多個(gè)驅(qū)動(dòng)程序台盯。
下圖是我看到的一個(gè)比較好的 JDBC 架構(gòu)模型圖(后面會(huì)對(duì)這張圖做出詳細(xì)的解釋?zhuān)?/p>
我個(gè)人把使用 JDBC 劃分為了以下六個(gè)步驟:
- 加載驅(qū)動(dòng)
- 創(chuàng)建鏈接對(duì)象
- 創(chuàng)建 sql 命令對(duì)象
- 執(zhí)行 sql 命令
- 判斷執(zhí)行結(jié)果
- 關(guān)閉資源
以上步驟就好比是打電話讓朋友幫忙辦件事兒首妖,首先你得有個(gè)手機(jī)(加載驅(qū)動(dòng)),然后利用手機(jī)給朋友打電話(創(chuàng)建鏈接對(duì)象)爷恳,朋友接到電話(創(chuàng)建 sql 命令對(duì)象)然后執(zhí)行你的要求(執(zhí)行 sql 命令),執(zhí)行命令之后朋友給你一個(gè)反饋澳迫,你來(lái)對(duì)這個(gè)反饋進(jìn)行處理(判斷執(zhí)行結(jié)果)捶牢,最后掛斷電話(關(guān)閉資源)询吴。
常見(jiàn)的 JDBC 組件
JDBC API 提供以下接口和類(lèi):
- DriverManager:此類(lèi)管理數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序(也就是 Driver)。使用某種協(xié)議(無(wú)需糾結(jié)是什么協(xié)議)將來(lái)自 java 應(yīng)用程序的連接請(qǐng)求與適當(dāng)?shù)臄?shù)據(jù)庫(kù)驅(qū)動(dòng)程序進(jìn)行匹配栈虚,然后進(jìn)行一系列操作連接到數(shù)據(jù)庫(kù)。
- Driver:此接口處理與數(shù)據(jù)庫(kù)服務(wù)器的通信史隆,我們很少會(huì)直接與 Driver 對(duì)象進(jìn)行交互魂务,但會(huì)使用上面提到的 DriverManager 對(duì)象來(lái)管理這種類(lèi)型的對(duì)象。
- Connection:此接口具有用于聯(lián)系數(shù)據(jù)庫(kù)的所有方法泌射,與數(shù)據(jù)庫(kù)的所有通信都是通過(guò)該對(duì)象完成的粘姜。
- Statement:使用此接口創(chuàng)建的對(duì)象將 sql 語(yǔ)句提交到數(shù)據(jù)庫(kù),執(zhí)行 sql 命令熔酷。
- PreparedStatement:此接口和 Statement 接口類(lèi)似孤紧,用此接口創(chuàng)建的對(duì)象執(zhí)行 sql 命令。
- ** ResultSet**:執(zhí)行 sql 語(yǔ)句查詢后拒秘,將返回后的數(shù)據(jù)存放在該對(duì)象中号显。
具體 JDBC 應(yīng)用程序
1、向數(shù)據(jù)庫(kù)插入數(shù)據(jù)
//導(dǎo)入需要的包躺酒,大多數(shù)情況下押蚤,使用 import java.sql.* 應(yīng)該就足夠了
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJdbc {
public static void main(String[] args) throws ClassNotFoundException, SQLException{
//1、加載 JDBC 驅(qū)動(dòng)
Class.forName("oracle.jdbc.OracleDriver");
//2羹应、利用驅(qū)動(dòng)創(chuàng)建鏈接對(duì)象
Connection conn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","(數(shù)據(jù)庫(kù)賬戶名)","(密碼)");
//3揽碘、創(chuàng)建 sql 命令對(duì)象并創(chuàng)建 sql 語(yǔ)句
String sql="insert into tdept values('x','xxx','x')";//往數(shù)據(jù)庫(kù)插入數(shù)據(jù)
Statement stmt =conn.createStatement();
//4、執(zhí)行 sql 命令并獲取處理結(jié)果(是否插入成功)
int i=stmt.executeUpdate(sql);
//5、處理結(jié)果
if(i>0){
System.out.println("插入成功");
}else{
System.out.println("插入失敗");
}
//6钾菊、關(guān)閉資源
stmt.close();
conn.close();
}
}
這段代碼屬于向數(shù)據(jù)庫(kù)中插入數(shù)據(jù)帅矗,所以不用 ResultSet 對(duì)象,對(duì)于數(shù)據(jù)的增煞烫、刪浑此、改一般返回值都是一個(gè) int 型數(shù)值(此處命名為 i),當(dāng)對(duì)數(shù)據(jù)操作成功后返回值 i 為1滞详,否則凛俱,返回值為 -1。
而對(duì)于數(shù)據(jù)的查詢一般都是需要用 ResultSet 對(duì)象來(lái)接住返回結(jié)果的料饥。
2蒲犬、查詢數(shù)據(jù)庫(kù)中的數(shù)據(jù)(加入異常處理)
//導(dǎo)入需要的包
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestSelect {
public static void main(String[] args){
//聲明鏈接參數(shù)
String url="jdbc:oracle:thin:@localhost:1521:orcl";
String user="scott";
String pwd="123";
String driver="oracle.jdbc.OracleDriver";
//聲明jdbc變量
Connection conn=null;
Statement stmt =null;
ResultSet rs=null;
try {
//加載驅(qū)動(dòng)
Class.forName(driver);
//創(chuàng)建鏈接對(duì)象
conn=DriverManager.getConnection(url,user,pwd);
//創(chuàng)建 sql 命令對(duì)象并執(zhí)行 sql 命令
String sql="select * from emp";
stmt=conn.createStatement();
//獲取結(jié)果
rs=stmt.executeQuery(sql);
//處理結(jié)果
System.out.println("學(xué)號(hào)\t姓名\t班級(jí)");
while(rs.next()){
System.out.println(rs.getInt("deptno")+"\t"+rs.getString("daname")+"\t"+rs.getString("loc"));
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//關(guān)閉資源
try {
stmt.close();
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
這段代碼可以看成是用 JDBC 的正常步驟,先聲明鏈接對(duì)象岸啡、聲明 jdbc 對(duì)象原叮,然后執(zhí)行上面的六個(gè)步驟。
也許你會(huì)問(wèn)巡蘸,為啥是這幾個(gè)步驟呢奋隶,因?yàn)?.. ... 沒(méi)有原因,就這么來(lái)用的悦荒,別在沒(méi)必要的地方糾結(jié)唯欣。
到這里可能會(huì)有人對(duì) ResultSet 有疑問(wèn),ResultSet 到底是個(gè)什么東東搬味?其實(shí)可以把 ResultSet 看成一個(gè)迭代器:
最開(kāi)始的時(shí)候境氢,指針處于黑色線條處,當(dāng) sql 語(yǔ)句被執(zhí)行之后碰纬,返回的數(shù)據(jù)儲(chǔ)存在 Resultset 中(如果有的話)萍聊,然后當(dāng)程序執(zhí)行到 rs.next() 的時(shí)候,指針下移悦析,指向返回的第一條數(shù)據(jù)脐区,如果這條數(shù)據(jù)不為空(也就是說(shuō)有返回的數(shù)據(jù))時(shí),rs.next() 為 true她按,然后進(jìn)入 while 循環(huán)對(duì)返回的數(shù)據(jù)進(jìn)行操作牛隅。
PreparedStatement 對(duì)象與 Statement 對(duì)象
在這里需要對(duì)這兩個(gè)對(duì)象進(jìn)行一定的解釋但不深究,其實(shí)也沒(méi)必要深究酌泰,自從我用 jdbc 以來(lái)媒佣,基本上都是用的 PreparedStatement對(duì)象,很少用 Statement陵刹,在此處就不深入探討了還請(qǐng)見(jiàn)諒默伍。
- 使用 PreparedStatement可以防止 sql 注入(有興趣的同學(xué)可以參考 sql 注入原理講解),因?yàn)樵趧?chuàng)建此對(duì)象的時(shí)候已經(jīng)將SQL傳入,這樣可以針對(duì)性的進(jìn)行賦值.
- PreparedStatement 的執(zhí)行效率比 Statement 高
且看以下代碼:
//導(dǎo)入包
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
public class TestPreparedStatement {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//創(chuàng)建鏈接參數(shù)
//聲明jdbc變量
//加載驅(qū)動(dòng)
Class.forName("oracle.jdbc.OracleDriver");
//創(chuàng)建鏈接對(duì)象
Connection conn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "(數(shù)據(jù)庫(kù)賬戶)","(數(shù)據(jù)庫(kù)密碼)");
//創(chuàng)建 sql 命令對(duì)象并發(fā)送 sql 命令
String sql="insert into t_user values(?,?,?)";
& PreparedStatement ps=conn.prepareStatement(sql);
//PreparedStatement 可以給字段針對(duì)性的進(jìn)行賦值
ps.setInt(1,6);
ps.setString(2,"李四");
ps.setString(3,"123");
&& int i=ps.executeUpdate();
//使用 Statement 的寫(xiě)法
String sql2="insert into t_user values(5,'張三','123')";
& Statement st=conn.createStatement();
&& int j=st.executeUpdate(sql2);
//獲取結(jié)果
//處理結(jié)果
//關(guān)閉資源
}
}
從上面的代碼可以看出(為了方便大家對(duì)比也糊,不產(chǎn)生冗余炼蹦,獲取結(jié)果之后的代碼在這里就不寫(xiě)出來(lái)了),創(chuàng)建 sql 命令對(duì)象的方式不同(標(biāo)&處)狸剃,另外執(zhí)行 sql 命令的方式也不相同(標(biāo)&&處)掐隐,而且** PreparedStatement 可以給字段針對(duì)性的進(jìn)行賦值**,這點(diǎn)是這是 Statement 所不具備的钞馁,一般使用過(guò)程中使用 PreparedStatement 較多虑省。
以上這些是兩者使用方式的不同,個(gè)人覺(jué)得不需要深究僧凰,如果不理解探颈,敲代碼,敲代碼训措,敲代碼N苯凇!绩鸣!學(xué)習(xí)一門(mén)技術(shù)如果只是紙上談兵怀大,永遠(yuǎn)也學(xué)不好,看完之后更重要的是要實(shí)踐全闷,畢竟實(shí)踐是檢驗(yàn)真理的唯一標(biāo)準(zhǔn),而且你親自多敲幾遍代碼會(huì)對(duì)知識(shí)有更深的理解萍启。
以上只是個(gè)人的愚見(jiàn)总珠,如有不妥之處,還請(qǐng)指出勘纯,一定改進(jìn)局服!