1.1JDBC概述
JDBC(Java?Data?Base?Connectivity,java數(shù)據(jù)庫(kù)連接)是一種用于執(zhí)行SQL語(yǔ)句的Java?API狸相,可以為多種關(guān)系數(shù)據(jù)庫(kù)提供統(tǒng)一訪問刮吧,它由一組用Java語(yǔ)言編寫的類和接口組成盒件。是Java訪問數(shù)據(jù)庫(kù)的標(biāo)準(zhǔn)規(guī)范
JDBC提供了一種基準(zhǔn),據(jù)此可以構(gòu)建更高級(jí)的工具和接口,使數(shù)據(jù)庫(kù)開發(fā)人員能夠編寫數(shù)據(jù)庫(kù)應(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ù)庫(kù)規(guī)范稱為JDBC,而生產(chǎn)廠商提供規(guī)范的實(shí)現(xiàn)類稱為驅(qū)動(dòng)崎弃。
JDBC是接口甘晤,驅(qū)動(dòng)是接口的實(shí)現(xiàn)含潘,沒有驅(qū)動(dòng)將無法完成數(shù)據(jù)庫(kù)連接,從而不能操作數(shù)據(jù)庫(kù)线婚!每個(gè)數(shù)據(jù)庫(kù)廠商都需要提供自己的驅(qū)動(dòng)遏弱,用來連接自己公司的數(shù)據(jù)庫(kù),也就是說驅(qū)動(dòng)一般都由數(shù)據(jù)庫(kù)生成廠商提供塞弊。
1.3JDBC開發(fā)步驟
1.注冊(cè)驅(qū)動(dòng).
2.獲得連接.
3.獲得語(yǔ)句執(zhí)行平臺(tái)
4.執(zhí)行sql語(yǔ)句
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诀黍,所以我們可以通過如下語(yǔ)句進(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ù)庫(kù)的位置(網(wǎng)址)user用戶名password密碼
url比較復(fù)雜歇拆,下面是mysql的url:
jdbc:mysql://localhost:3306/mydb
JDBC規(guī)定url的格式由三部分組成,每個(gè)部分中間使用冒號(hào)分隔范咨。
l第一部分是jdbc故觅,這是固定的;
l第二部分是數(shù)據(jù)庫(kù)名稱渠啊,那么連接mysql數(shù)據(jù)庫(kù)输吏,第二部分當(dāng)然是mysql了;
l第三部分是由數(shù)據(jù)庫(kù)廠商規(guī)定的替蛉,我們需要了解每個(gè)數(shù)據(jù)庫(kù)廠商的要求贯溅,mysql的第三部分分別由數(shù)據(jù)庫(kù)服務(wù)器的IP地址(localhost)、端口號(hào)(3306)躲查,以及DATABASE名稱(mydb)組成它浅。
1.3.4API詳解:獲得語(yǔ)句執(zhí)行平臺(tái)
String?sql?=?"某SQL語(yǔ)句";
獲取Statement語(yǔ)句執(zhí)行平臺(tái):Statement?stmt?=?con.createStatement();
常用方法:
nint?executeUpdate(String?sql);?--執(zhí)行insert?update?delete語(yǔ)句.
nResultSet?executeQuery(String?sql);?--執(zhí)行select語(yǔ)句.
nboolean?execute(String?sql);?--執(zhí)行select返回true執(zhí)行其他的語(yǔ)句返回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語(yǔ)句如下:
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í)影所,上述查詢語(yǔ)句時(shí)永遠(yuǎn)可以查詢出結(jié)果的。那么用戶就直接登錄成功了僚碎,顯然我們不希望看到這樣的結(jié)果猴娩,這便是SQL注入問題。
為此勺阐,我們使用PreparedStatement來解決對(duì)應(yīng)的問題卷中。
1.5API詳解:預(yù)處理對(duì)象
使用PreparedStatement預(yù)處理對(duì)象時(shí),建議每條sql語(yǔ)句所有的實(shí)際參數(shù)渊抽,都使用逗號(hào)分隔蟆豫。
String?sql?=?"insert?into?sort(sid,sname)?values(?,?)";;
PreparedStatement預(yù)處理對(duì)象代碼:
PreparedStatement?psmt?=?conn.prepareStatement(sql)
常用方法:
1.執(zhí)行SQL語(yǔ)句:
lint?executeUpdate();?--執(zhí)行insert?update?delete語(yǔ)句.
lResultSet?executeQuery();?--執(zhí)行select語(yǔ)句.
lboolean?execute();?--執(zhí)行select返回true?執(zhí)行其他的語(yǔ)句返回false.
2.設(shè)置實(shí)際參數(shù)
lvoidsetXxx(intindex,Xxxxx)?將指定參數(shù)設(shè)置為給定Java的xx值。在將此值發(fā)送到數(shù)據(jù)庫(kù)時(shí)懒闷,驅(qū)動(dòng)程序?qū)⑺D(zhuǎn)換成一個(gè)?SQLXxx類型值十减。
例如:
setString(2,?"家用電器")把SQL語(yǔ)句中第2個(gè)位置的占位符??替換成實(shí)際參數(shù)"家用電器"
1.6預(yù)處理對(duì)象executeUpdate方法
通過預(yù)處理對(duì)象的executeUpdate方法愤估,完成記錄的insert\update\delete語(yǔ)句的執(zhí)行帮辟。操作格式統(tǒng)一如下:
1.注冊(cè)驅(qū)動(dòng)
2.獲取連接
3.獲取預(yù)處理對(duì)象
4.?SQL語(yǔ)句占位符設(shè)置實(shí)際參數(shù)
5.執(zhí)行SQL語(yǔ)句
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語(yǔ)句占位符設(shè)置實(shí)際參數(shù)
stat.setString(1,"奢侈品");
//?5執(zhí)行SQL語(yǔ)句
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語(yǔ)句占位符設(shè)置實(shí)際參數(shù)
stat.setString(1,"數(shù)碼產(chǎn)品");
stat.setInt(2,?1);
//?5執(zhí)行SQL語(yǔ)句
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語(yǔ)句占位符設(shè)置實(shí)際參數(shù)
stat.setInt(1,?1);
//?5執(zhí)行SQL語(yǔ)句
intline=stat.executeUpdate();
System.out.println("刪除記錄數(shù):"+line);
//6釋放資源
stat.close();
conn.close();
}
1.7預(yù)處理對(duì)象executeQuery方法
通過預(yù)處理對(duì)象的executeQuery方法,完成記錄的select語(yǔ)句的執(zhí)行玩焰。操作格式統(tǒng)一如下:
1.注冊(cè)驅(qū)動(dòng)
2.獲取連接
3.獲取預(yù)處理對(duì)象
4.?SQL語(yǔ)句占位符設(shè)置實(shí)際參數(shù)
5.執(zhí)行SQL語(yǔ)句
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語(yǔ)句占位符設(shè)置實(shí)際參數(shù)
//?5執(zhí)行SQL語(yǔ)句
ResultSetrs=stat.executeQuery();
//6處理結(jié)果集(遍歷結(jié)果集合)
while(rs.next()?){
//獲取當(dāng)前行的分類ID
Stringsid=rs.getString("sid");//方法參數(shù)為數(shù)據(jù)庫(kù)表中的列名
//獲取當(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語(yǔ)句占位符設(shè)置實(shí)際參數(shù)
stat.setString(1,"奢侈品");
//5執(zhí)行SQL語(yǔ)句
ResultSetrs=stat.executeQuery();
//6處理結(jié)果集(遍歷結(jié)果集合)
while(rs.next()?){
//獲取當(dāng)前行的分類ID
Stringsid=rs.getString("sid");//方法參數(shù)為數(shù)據(jù)庫(kù)表中的列名
//獲取當(dāng)前行的分類名稱
Stringsname=rs.getString("sname");
//顯示數(shù)據(jù)
System.out.println(sid+"-----"+sname);
}
//7釋放資源
rs.close();
stat.close();
conn.close();
}
1.8JDBC工具類
“獲得數(shù)據(jù)庫(kù)連接”操作由驹,將在以后的增刪改查所有功能中都存在,可以封裝工具類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ù)庫(kù)驅(qū)動(dòng)注冊(cè)失斏!!");
}
}
//提供獲取連接的方法
publicstaticConnection?getConn()throwsException?{
//?2.獲得連接
Connectionconn=?DriverManager.getConnection(URL,USER,PASSWORD);
//返回連接
returnconn;
}
}