1.1JDBC概述
JDBC(Java?Data?Base?Connectivity,java數(shù)據(jù)庫連接)是一種用于執(zhí)行SQL語句的Java?API,可以為多種關(guān)系數(shù)據(jù)庫提供統(tǒng)一訪問,它由一組用Java語言編寫的類和接口組成。是Java訪問數(shù)據(jù)庫的標(biāo)準(zhǔn)規(guī)范
JDBC提供了一種基準(zhǔn),據(jù)此可以構(gòu)建更高級(jí)的工具和接口,使數(shù)據(jù)庫開發(fā)人員能夠編寫數(shù)據(jù)庫應(yīng)用程序。
JDBC需要連接驅(qū)動(dòng),驅(qū)動(dòng)是兩個(gè)設(shè)備要進(jìn)行通信,滿足一定通信數(shù)據(jù)格式,數(shù)據(jù)格式由設(shè)備提供商規(guī)定,設(shè)備提供商為設(shè)備提供驅(qū)動(dòng)軟件,通過軟件可以與該設(shè)備進(jìn)行通信。
1.2JDBC原理
Java提供訪問數(shù)據(jù)庫規(guī)范稱為JDBC,而生產(chǎn)廠商提供規(guī)范的實(shí)現(xiàn)類稱為驅(qū)動(dòng)。
JDBC是接口,驅(qū)動(dòng)是接口的實(shí)現(xiàn),沒有驅(qū)動(dòng)將無法完成數(shù)據(jù)庫連接,從而不能操作數(shù)據(jù)庫!每個(gè)數(shù)據(jù)庫廠商都需要提供自己的驅(qū)動(dòng),用來連接自己公司的數(shù)據(jù)庫,也就是說驅(qū)動(dòng)一般都由數(shù)據(jù)庫生成廠商提供。
1.3JDBC開發(fā)步驟
1.注冊(cè)驅(qū)動(dòng).
2.獲得連接.
3.獲得語句執(zhí)行平臺(tái)
4.執(zhí)行sql語句
5.處理結(jié)果
6.釋放資源.
1.3.1導(dǎo)入驅(qū)動(dòng)jar包
創(chuàng)建lib目錄,用于存放當(dāng)前項(xiàng)目需要的所有jar包
選擇jar包,右鍵執(zhí)行build?path?/?Add?to?Build?Path
1.3.2API詳解:注冊(cè)驅(qū)動(dòng)
代碼:Class.forName("com.mysql.jdbc.Driver");
JDBC規(guī)范定義驅(qū)動(dòng)接口:java.sql.Driver,MySql驅(qū)動(dòng)包提供了實(shí)現(xiàn)類:com.mysql.jdbc.Driver
DriverManager工具類,提供注冊(cè)驅(qū)動(dòng)的方法registerDriver(),方法的參數(shù)是java.sql.Driver,所以我們可以通過如下語句進(jìn)行注冊(cè):
DriverManager.registerDriver(new?com.mysql.jdbc.Driver());
以上代碼不推薦使用,存在兩方面不足
1.硬編碼,后期不易于程序擴(kuò)展和維護(hù)
2.驅(qū)動(dòng)被注冊(cè)兩次。
通常開發(fā)我們使用Class.forName()加載一個(gè)使用字符串描述的驅(qū)動(dòng)類。
如果使用Class.forName()將類加載到內(nèi)存,該類的靜態(tài)代碼將自動(dòng)執(zhí)行。
通過查詢com.mysql.jdbc.Driver源碼,我們發(fā)現(xiàn)Driver類“主動(dòng)”將自己進(jìn)行注冊(cè)
public?class?Driver?extends?NonRegisteringDriver?implements?java.sql.Driver?{
static?{
try?{
java.sql.DriverManager.registerDriver(new?Driver());
}?catch?(SQLException?E)?{
throw?new?RuntimeException("Can't?register?driver!");
}
}
……
}
1.3.3API詳解:獲得鏈接
代碼:Connection?con?=?DriverManager.getConnection
(“jdbc:mysql://localhost:3306/mydb”,”root”,”root”);
獲取連接需要方法DriverManager.getConnection(url,username,password),三個(gè)參數(shù)分別表示,url需要連接數(shù)據(jù)庫的位置(網(wǎng)址)user用戶名password密碼
url比較復(fù)雜,下面是mysql的url:
jdbc:mysql://localhost:3306/mydb
JDBC規(guī)定url的格式由三部分組成,每個(gè)部分中間使用冒號(hào)分隔。
l第一部分是jdbc,這是固定的;
l第二部分是數(shù)據(jù)庫名稱,那么連接mysql數(shù)據(jù)庫,第二部分當(dāng)然是mysql了;
l第三部分是由數(shù)據(jù)庫廠商規(guī)定的,我們需要了解每個(gè)數(shù)據(jù)庫廠商的要求,mysql的第三部分分別由數(shù)據(jù)庫服務(wù)器的IP地址(localhost)、端口號(hào)(3306),以及DATABASE名稱(mydb)組成。
1.3.4API詳解:獲得語句執(zhí)行平臺(tái)
String?sql?=?"某SQL語句";
獲取Statement語句執(zhí)行平臺(tái):Statement?stmt?=?con.createStatement();
常用方法:
nint?executeUpdate(String?sql);?--執(zhí)行insert?update?delete語句.
nResultSet?executeQuery(String?sql);?--執(zhí)行select語句.
nboolean?execute(String?sql);?--執(zhí)行select返回true執(zhí)行其他的語句返回false.
1.3.5API詳解:處理結(jié)果集(執(zhí)行insert、update、delete無需處理)
ResultSet實(shí)際上就是一張二維的表格,我們可以調(diào)用其boolean?next()方法指向某行記錄,當(dāng)?shù)谝淮握{(diào)用next()方法時(shí),便指向第一行記錄的位置,這時(shí)就可以使用ResultSet提供的getXXX(int?col)方法(與索引從0開始不同個(gè),列從1開始)來獲取指定列的數(shù)據(jù):
rs.next();//指向第一行
rs.getInt(1);//獲取第一行第一列的數(shù)據(jù)
常用方法:
nObject?getObject(intindex)/?Object?getObject(String?name)獲得任意對(duì)象
nString?getString(intindex)/?Object?getObject(String?name)獲得字符串
nint?getInt(intindex)/?Object?getObject(String?name)獲得整形
ndouble?getDouble(intindex)/?Object?getObject(String?name)獲得雙精度浮點(diǎn)型
1.3.6API詳解:釋放資源
與IO流一樣,使用后的東西都需要關(guān)閉!關(guān)閉的順序是先得到的后關(guān)閉,后得到的先關(guān)閉。
rs.close();
stmt.close();
con.close();
1.4SQL注入問題
假設(shè)有登錄案例SQL語句如下:
SELECT?*?FROM用戶表WHERE?NAME?=用戶輸入的用戶名AND?PASSWORD?=用戶輸?shù)拿艽a;
此時(shí),當(dāng)用戶輸入正確的賬號(hào)與密碼后,查詢到了信息則讓用戶登錄。但是當(dāng)用戶輸入的賬號(hào)為XXX密碼為:XXX’OR‘a(chǎn)’=’a時(shí),則真正執(zhí)行的代碼變?yōu)椋?/p>
SELECT?*?FROM用戶表WHERE?NAME?=‘XXX’AND?PASSWORD?=’XXX’OR’a’=’a’;
此時(shí),上述查詢語句時(shí)永遠(yuǎn)可以查詢出結(jié)果的。那么用戶就直接登錄成功了,顯然我們不希望看到這樣的結(jié)果,這便是SQL注入問題。
為此,我們使用PreparedStatement來解決對(duì)應(yīng)的問題。
1.5API詳解:預(yù)處理對(duì)象
使用PreparedStatement預(yù)處理對(duì)象時(shí),建議每條sql語句所有的實(shí)際參數(shù),都使用逗號(hào)分隔。
String?sql?=?"insert?into?sort(sid,sname)?values(?,?)";;
PreparedStatement預(yù)處理對(duì)象代碼:
PreparedStatement?psmt?=?conn.prepareStatement(sql)
常用方法:
1.執(zhí)行SQL語句:
lint?executeUpdate();?--執(zhí)行insert?update?delete語句.
lResultSet?executeQuery();?--執(zhí)行select語句.
lboolean?execute();?--執(zhí)行select返回true?執(zhí)行其他的語句返回false.
2.設(shè)置實(shí)際參數(shù)
lvoidsetXxx(intindex,Xxxxx)?將指定參數(shù)設(shè)置為給定Java的xx值。在將此值發(fā)送到數(shù)據(jù)庫時(shí),驅(qū)動(dòng)程序?qū)⑺D(zhuǎn)換成一個(gè)?SQLXxx類型值。
例如:
setString(2,?"家用電器")把SQL語句中第2個(gè)位置的占位符??替換成實(shí)際參數(shù)"家用電器"
1.6預(yù)處理對(duì)象executeUpdate方法
通過預(yù)處理對(duì)象的executeUpdate方法,完成記錄的insert\update\delete語句的執(zhí)行。操作格式統(tǒng)一如下:
1.注冊(cè)驅(qū)動(dòng)
2.獲取連接
3.獲取預(yù)處理對(duì)象
4.?SQL語句占位符設(shè)置實(shí)際參數(shù)
5.執(zhí)行SQL語句
6.釋放資源
1.6.1插入記錄:insert
l實(shí)現(xiàn)向分類表中插入指定的新分類
publicvoiddemo01()throwsException?{
//?1注冊(cè)驅(qū)動(dòng)
Class.forName("com.mysql.jdbc.Driver");
//?2獲取連接
Connectionconn=?DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","root");
//?3獲得預(yù)處理對(duì)象
Stringsql="insert?into?sort(sname)?values(?)";
PreparedStatementstat=conn.prepareStatement(sql);
//?4SQL語句占位符設(shè)置實(shí)際參數(shù)
stat.setString(1,"奢侈品");
//?5執(zhí)行SQL語句
intline=stat.executeUpdate();
System.out.println("新添加記錄數(shù):"+line);
//6釋放資源
stat.close();
conn.close();
}
1.6.2更新記錄:update
l實(shí)現(xiàn)更新分類表中指定分類ID所對(duì)應(yīng)記錄的分類名稱
publicvoiddemo02()throwsException?{
//?1注冊(cè)驅(qū)動(dòng)
Class.forName("com.mysql.jdbc.Driver");
//?2獲取連接
Connectionconn=?DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","root");
//?3獲得預(yù)處理對(duì)象中
Stringsql="update?sort?set?sname=??where?sid=?";
PreparedStatementstat=conn.prepareStatement(sql);
//?4SQL語句占位符設(shè)置實(shí)際參數(shù)
stat.setString(1,"數(shù)碼產(chǎn)品");
stat.setInt(2,?1);
//?5執(zhí)行SQL語句
intline=stat.executeUpdate();
System.out.println("更新記錄數(shù):"+line);
//6釋放資源
stat.close();
conn.close();
}
1.6.3刪除記錄:delete
l實(shí)現(xiàn)刪除分類表中指定分類ID的記錄
publicvoiddemo03()throwsException?{
//?1注冊(cè)驅(qū)動(dòng)
Class.forName("com.mysql.jdbc.Driver");
//?2獲取連接
Connectionconn=?DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","root");
//?3獲得預(yù)處理對(duì)象
Stringsql="delete?from?sort?where?sid=?";
PreparedStatementstat=conn.prepareStatement(sql);
//?4SQL語句占位符設(shè)置實(shí)際參數(shù)
stat.setInt(1,?1);
//?5執(zhí)行SQL語句
intline=stat.executeUpdate();
System.out.println("刪除記錄數(shù):"+line);
//6釋放資源
stat.close();
conn.close();
}
1.7預(yù)處理對(duì)象executeQuery方法
通過預(yù)處理對(duì)象的executeQuery方法,完成記錄的select語句的執(zhí)行。操作格式統(tǒng)一如下:
1.注冊(cè)驅(qū)動(dòng)
2.獲取連接
3.獲取預(yù)處理對(duì)象
4.?SQL語句占位符設(shè)置實(shí)際參數(shù)
5.執(zhí)行SQL語句
6.處理結(jié)果集(遍歷結(jié)果集合)
7.釋放資源
1.7.1查詢記錄:select
l實(shí)現(xiàn)查詢分類表所有記錄
publicvoiddemo04()throwsException?{
//?1注冊(cè)驅(qū)動(dòng)
Class.forName("com.mysql.jdbc.Driver");
//?2獲取連接
Connectionconn=?DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","root");
//?3獲得預(yù)處理對(duì)象
Stringsql="select?*?from?sort";
PreparedStatementstat=conn.prepareStatement(sql);
//?4SQL語句占位符設(shè)置實(shí)際參數(shù)
//?5執(zhí)行SQL語句
ResultSetrs=stat.executeQuery();
//6處理結(jié)果集(遍歷結(jié)果集合)
while(rs.next()?){
//獲取當(dāng)前行的分類ID
Stringsid=rs.getString("sid");//方法參數(shù)為數(shù)據(jù)庫表中的列名
//獲取當(dāng)前行的分類名稱
Stringsname=rs.getString("sname");
//顯示數(shù)據(jù)
System.out.println(sid+"-----"+sname);
}
//7釋放資源
rs.close();
stat.close();
conn.close();
}
l實(shí)現(xiàn)查詢分類表中指定分類名稱的記錄
publicvoiddemo05()throwsException?{
//?1注冊(cè)驅(qū)動(dòng)
Class.forName("com.mysql.jdbc.Driver");
//?2獲取連接
Connectionconn=?DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","root");
//?3獲得預(yù)處理對(duì)象
Stringsql="select?*?from?sort?where?sname=?";
PreparedStatementstat=conn.prepareStatement(sql);
//?4SQL語句占位符設(shè)置實(shí)際參數(shù)
stat.setString(1,"奢侈品");
//5執(zhí)行SQL語句
ResultSetrs=stat.executeQuery();
//6處理結(jié)果集(遍歷結(jié)果集合)
while(rs.next()?){
//獲取當(dāng)前行的分類ID
Stringsid=rs.getString("sid");//方法參數(shù)為數(shù)據(jù)庫表中的列名
//獲取當(dāng)前行的分類名稱
Stringsname=rs.getString("sname");
//顯示數(shù)據(jù)
System.out.println(sid+"-----"+sname);
}
//7釋放資源
rs.close();
stat.close();
conn.close();
}
1.8JDBC工具類
“獲得數(shù)據(jù)庫連接”操作,將在以后的增刪改查所有功能中都存在,可以封裝工具類JDBCUtils。提供獲取連接對(duì)象的方法,從而達(dá)到代碼的重復(fù)利用。
該工具類提供方法:public?static?Connection?getConn?()。代碼如下:
/*
*?JDBC工具類
*/
publicclassJDBCUtils?{
publicstaticfinalStringDRIVERNAME="com.mysql.jdbc.Driver";
publicstaticfinalStringURL="jdbc:mysql://localhost:3306/mydb";
publicstaticfinalStringUSER="root";
publicstaticfinalStringPASSWORD="root";
static{
try{
Class.forName(DRIVERNAME);
}catch(ClassNotFoundExceptione)?{
System.out.println("數(shù)據(jù)庫驅(qū)動(dòng)注冊(cè)失敗!");
}
}
//提供獲取連接的方法
publicstaticConnection?getConn()throwsException?{
//?2.獲得連接
Connectionconn=?DriverManager.getConnection(URL,USER,PASSWORD);
//返回連接
returnconn;
}
}