好快,已經(jīng)是12月份了,11月5日開的班。就快學習一個月了,總學習時間是四個月。過年休息9天,這樣到明年3月14日課程就結(jié)束了。好好學習,回去找個好工作!
今日是JDBC的第一天,JDBC的基礎(chǔ)應(yīng)用。以后在WEB開發(fā)中的使用方式。課程中,方老師上午在講解JDBC基礎(chǔ)的同時做了一個JDBC練習程序,對JDBC的基礎(chǔ)應(yīng)用。下午,方老師做了一個使用數(shù)據(jù)庫的WEB應(yīng)用,用戶注冊、登錄、用戶信息修改。
先讓我們來了解一下JDBC(Java Data Base Connectivity)基礎(chǔ)吧!
我們都知道數(shù)據(jù)庫都提供一些接口,用戶使用這些接口操作數(shù)據(jù)庫。這就是數(shù)據(jù)庫驅(qū)動!常見的數(shù)據(jù)庫有MySQL、Oracle、SQLServer、DB2等,這些數(shù)據(jù)庫提供的接口都不一樣,難道開發(fā)人員使用不同的數(shù)據(jù)庫就要學習不同的驅(qū)動接口嗎?JDBC正是為統(tǒng)一數(shù)據(jù)庫訪問接口而實現(xiàn)的,SUN公司提出了這一接口。數(shù)據(jù)庫公司都去實現(xiàn)這一接口。大大方便了,編程人員對數(shù)據(jù)庫的操作:
在工程中使用JDBC,必須導入相應(yīng)的JAR包。比如使用MySQL數(shù)據(jù)庫,必須導入MySQL實現(xiàn)的JDBC jar包。可以到http://dev.mysql.com/downloads/下載。
使用JDCB進行數(shù)據(jù)訪問的基本流程,見代碼:
-
import java.sql.Connection;
-
import java.sql.DriverManager;
-
import java.sql.ResultSet;
-
import java.sql.SQLException;
-
import java.sql.Statement;
-
public class JDBCTemp {
-
public static void main(String[] main) throws Exception {
-
// 1.裝
-
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
-
/*
-
* 因om.mysql.jdbc.Driver在
-
* 上om.mysql.jdbc.Driver,
-
* 所
-
*/
-
Class.forName("com.mysql.jdbc.Driver");
-
// 2.連
-
Connection conn = DriverManager.getConnection(
-
"jdbc:mysql://localhost:3306/databasename", "username",
-
"password");
-
// 3.創(chuàng)QL語tatement對
-
Statement sta = conn.createStatement();
-
// 4.執(zhí)QL語
-
boolean ok = sta.execute("select * from user;");
-
-
// 5.遍
-
ResultSet rs = null;
-
if(ok){
-
rs = sta.getResultSet();
-
while(rs.next()){
-
rs.getInt(1);
-
//...
-
}
-
}
-
-
// 6.釋esultSet、tatement、onnection這
-
// 必
-
// 下
-
if(rs != null){
-
try {
-
rs.close();
-
} catch (SQLException e) {
-
e.printStackTrace();
-
}
-
rs = null;
-
}
-
-
if(sta != null){
-
try {
-
sta.close();
-
} catch (SQLException e) {
-
e.printStackTrace();
-
}
-
sta = null;
-
}
-
-
if(conn != null){
-
try {
-
conn.close();
-
} catch (SQLException e) {
-
e.printStackTrace();
-
}
-
conn = null;
-
}
-
}
-
}
上面的代碼只為演示,繼續(xù)向下學習就會發(fā)現(xiàn)其中的一些問題。
其中
DriverManager.getConnection("jdbc:mysql://localhost:3306/databasename", "username","password"); |
GetConnection的第一個參數(shù)“jdbc:mysql://localhost:3306/databasename
”,它的各段含義如下:
Jdbc:協(xié)議
Mysql:子協(xié)議
localhost:主機
3306:端口
databasename:數(shù)據(jù)庫名
常見的URL如下:
Oracle :jdbc:oracle:thin:@localhost:1521:sid
SQLServer:jdbc:microsoft:sqlserver//localhost:1433; DatabaseName=sid
MYSQL:jdbc:mysql://localhost:3306/sid
如果把上面的代碼用于用戶登錄或查詢數(shù)據(jù)時,會造成一個嚴重的安全漏洞——SQL注入!
例,根據(jù)提交的用戶名查找用戶:
"select id,name,password from user where name='"+name+"'"; |
如果用戶提交的用戶名是:“’ or 1=1 or 1=‘”,會發(fā)生什么問題?因為在where過濾時使用了or邏輯,其有的1=1返回真,結(jié)果可以正常通過驗證。這是一個十分嚴重的安全漏洞!
為此Java為我們提供了PreparedStatement接口,表示預(yù)編譯的 SQL 語句的對象。SQL 語句被預(yù)編譯并存儲在 PreparedStatement 對象中,然后可以使用此對象多次高效地執(zhí)行該語句。PreparedStatement的使用:
PreparedStatement ps = conn.prepareStatement("select id,name,password form user where name=? and passowrd=?"); ps.setString(1, name); ps.setString(2, password); |
這樣就可以解決SQL注入的漏洞,同時也可以高效的執(zhí)行SQL語句。上面的使用方法一眼就看出來了,一個“?”對應(yīng)下邊的ps.setXXX方法,按照“?”先后,對應(yīng)ps.setXXX第一個參數(shù)的索引!
我們使用Statement. execute執(zhí)行了查詢語句,Statement還有其他以execute開頭的方法,具體針對查詢和增加、刪除、修改的方法,在此就不一一說明了。JDK手冊里邊有詳細說明。
查詢成功后,在Statement對象中,可以獲得記錄集對象ResultSet,查詢的結(jié)果全都保存在ResultSet中嗎?仔細想想,好像是。如果有1億條記錄符合查詢條件,同時有1000個用戶調(diào)用同一查詢,那服務(wù)器不燒了嗎!所以查詢的結(jié)果并未保存在ResultSet中,而是保存在數(shù)據(jù)庫中,ResultSet指向數(shù)據(jù)庫的引用。這樣很方便也很快捷!那數(shù)據(jù)庫會不會被充爆了?當然不會,數(shù)據(jù)本身就保存在數(shù)據(jù)庫中,數(shù)據(jù)庫的查詢結(jié)果頂多就保存的指向數(shù)據(jù)的“指針”。
ResultSet對象內(nèi)部有一個游標,游標初始位置是第一條記錄前。必須調(diào)用它的next()方法,才會到第一條記錄,依次向下。如果不存在記錄,或者已經(jīng)到記錄尾,則返回false。存在記錄返回true。然后我們可以通過調(diào)用它的getObject、getInt、getString…方法調(diào)用相應(yīng)的值,如果只使用getObject獲取記錄值,必須使用強轉(zhuǎn)將它轉(zhuǎn)換為我們需要的類型。
下面是常用數(shù)據(jù)類型轉(zhuǎn)換表(老方整理的,嘿嘿):
SQL類型 |
Jdbc對應(yīng)方法 |
返回類型 |
BIT |
getBoolean() |
Boolean |
TINYINT |
getByte() |
Byte |
SMALLINT |
getShort() |
Short |
int |
getInt() |
Int |
BIGINT |
getLong() |
Long |
CHAR,VARCHAR,LONGVARCHAR |
getString() |
String |
Text Blob |
getColb() getBlob() |
Clob blob |
DATE |
getDate() |
Java.sql.Date |
TIME |
getTime() |
Java.sql.Time |
TIMESTAMP |
getTimestamp() |
Java.sql.Timestamp |
關(guān)于使用JDBC進行CURD的操作比較簡單,因為昨天已經(jīng)學習了在控制臺有使用這些操作,在此就不多進行復(fù)習了。但一定要記住每次使用完數(shù)據(jù)庫連接時,一定要釋放。一是因為數(shù)據(jù)庫有同時連接數(shù)量限制,二是因為數(shù)據(jù)連接會占用服務(wù)器資源。安全釋放這些連接,參看上邊的釋放代碼。常規(guī)的項目開發(fā)中,會將對數(shù)據(jù)庫的操作封裝到一個類中,這樣方便使用。
在常規(guī)項目開發(fā)中,我們需要編寫操作數(shù)據(jù)的DAO類。因為對數(shù)據(jù)庫的一些操作需要處理異常,為了查錯直觀一些。我們在環(huán)繞這些異常時,將它們包裝一下再拋出。如何包裝異常?JAVA的包裝類很多,我們的包裝也是通過這個方法實現(xiàn)的。編寫一個繼承處Exception類的子類,然后將接收的異常存到父親類中,我們也可以在自定義類中添加些自己的提示信息。這樣當程序運行時拋出的異常,可以直觀的定位到錯誤類。這是一個十分好的方法,用在其他地方。也有相當?shù)墓πВ?
最后一個問題,數(shù)據(jù)庫中的中文亂碼問題。其實并不是數(shù)據(jù)庫的原因 ,因為我們在創(chuàng)建數(shù)據(jù)庫時可以指定它的編碼為utf8、gb2312或gbk等支持中文的編碼。WEB應(yīng)用讀寫數(shù)據(jù)庫時造成的亂碼,主要是由于WEB應(yīng)用使用的編碼與數(shù)據(jù)庫使用的編碼不統(tǒng)一。統(tǒng)一一下,就可以解決了!
老方有給大家留作業(yè),今天的作業(yè)內(nèi)容較多。主要是為了練習數(shù)據(jù)庫的操作和數(shù)據(jù)庫與WEB的組合應(yīng)用。之前都是使用XML或配置文件做為偽數(shù)據(jù)庫與WEB組合練習的,從今天起用上數(shù)據(jù)庫了。雖然并不是十分興奮,但離框架和項目練習越來越近了,這讓我感覺很好!
以前并未使用JAVA開發(fā)過項目,雖然學習JAVA對我已經(jīng)沒什么難度。但上課這些天來,有時用到IO和集合,還是讓我卡了一下。因為我并未系統(tǒng)的學習過它們,我應(yīng)該系統(tǒng)的學習一下它們了。越是學習應(yīng)該越是快樂,越學習應(yīng)該越是簡單。沒有學習基礎(chǔ)那么枯燥,就圍繞那基礎(chǔ)搞來搞去,用起來了才舒服。因為基礎(chǔ)學習好了,所以感覺應(yīng)用就簡單的。其實應(yīng)用并不簡單,即使不說基礎(chǔ),應(yīng)用中的模式與框架是相當重要的,有使用過程語言開發(fā)的同志,我想對此有很大的感想!
我要學好項目的架構(gòu),文檔的編寫與項目管理,這在以后工作中是相當重要的。