1. JDBC的簡(jiǎn)介
概述: 就是Java用來(lái)操作不同數(shù)據(jù)庫(kù)(DBMS)的類庫(kù)(技術(shù)), 本質(zhì)就是一些類和接口.
/*
類: DriverManager
接口: Driver, Connection, Statement, PreparedStatement, ResultSet
*/
//Java Data Base Connectivity, Java數(shù)據(jù)庫(kù)連接(技術(shù)).
/*
集合: 就是Java用來(lái)存儲(chǔ)不同類型數(shù)據(jù)的容器, 本質(zhì)就是一些類和接口.
接口: Collection, Set, List, Map
類: ArrayList, HashSet, HashMap
面試題: 請(qǐng)求寫代碼實(shí)現(xiàn), 模擬棧的數(shù)據(jù)結(jié)構(gòu)(先進(jìn)后出)特點(diǎn)?
IO流: 就是Java用來(lái)傳輸數(shù)據(jù)的技術(shù), 本質(zhì)就是一些類和接口.
抽象類: InputStream, OutputStream, Reader, Writer
實(shí)現(xiàn)類: FileInputStream, BufferedInputStream, FileReader, BufferedReader
總結(jié): 集合的頂層都是接口, IO流的頂層都是抽象類.
*/
核心功能:
A: 連接數(shù)據(jù)庫(kù).
B: 向數(shù)據(jù)庫(kù)發(fā)送SQL語(yǔ)句.
C: 操作數(shù)據(jù)庫(kù)返回的 結(jié)果集.
如果操作的是更新語(yǔ)句(增刪改), 返回的結(jié)果集是: int 類型
如果操作的是查詢語(yǔ)句, 返回的結(jié)果集是: ResultSet 類型
- 什么是驅(qū)動(dòng)?
就是設(shè)備間進(jìn)行通信的橋梁.
- JDBC的原理是什么:
我們知道JDBC是用來(lái)操作不同數(shù)據(jù)庫(kù)的, 但是操作不同的數(shù)據(jù)庫(kù)需要使用不同的驅(qū)動(dòng).
eg: 我們想操作MySQL數(shù)據(jù)庫(kù), 就需要安裝MySQL的驅(qū)動(dòng), 我們想操作Oracle數(shù)據(jù)庫(kù), 就需要安裝Oracle數(shù)據(jù)庫(kù)的驅(qū)動(dòng), 如果我們操作SQLServer數(shù)據(jù)庫(kù),就需要安裝SQLServer數(shù)據(jù)庫(kù)的驅(qū)動(dòng), 這樣做是比較麻煩的. 因?yàn)镴ava已經(jīng)提供了大量的類和接口了, 但是要要求額外記憶一些其他的類和接口, 這樣就增加了程序員的學(xué)習(xí)難度. 后來(lái)Sun公司發(fā)現(xiàn)了這個(gè)問(wèn)題, 就和各大數(shù)據(jù)庫(kù)生產(chǎn)商協(xié)商決定, 由Sun公司提供統(tǒng)一的規(guī)范(就是一些類和接口), 數(shù)據(jù)庫(kù)生產(chǎn)商提供具體的實(shí)現(xiàn). Sun公司提供的這些類和接口就是: JDBC.
4. JDBC的代碼演示
A: 創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)web04.
B: 在數(shù)據(jù)庫(kù)web04中創(chuàng)建一個(gè)表(users);
create table users(
id int primary key auto_increment;
username varchar(20),
password varchar(20)
);
C: 往數(shù)據(jù)表中添加數(shù)據(jù).
insert into user values(null,'aaa','123');
insert into user values(null,'bbb','321');
insert into user values(null,'ccc','456');
insert into user values(null,'ddd','654');
D: 通過(guò)JDBC操作表數(shù)據(jù).
1) 導(dǎo)入驅(qū)動(dòng).
2) 注冊(cè)驅(qū)動(dòng).
3) 獲取連接對(duì)象.
4) 根據(jù)連接對(duì)象, 獲取可以操作SQL語(yǔ)句的對(duì)象.
5) 執(zhí)行SQL語(yǔ)句, 獲取結(jié)果集.
如果操作的是更新語(yǔ)句(增刪改), 返回的結(jié)果集是: int 類型
如果操作的是查詢語(yǔ)句, 返回的結(jié)果集是: ResultSet 類型
6) 操作結(jié)果集.
7) 釋放資源.
5. JDBC的API詳解之: DriverManager(類)
作用: 主要用于驅(qū)動(dòng)管理及獲取連接對(duì)象的.
作用一: 注冊(cè)驅(qū)動(dòng).
// MySQL的驅(qū)動(dòng)或者Oracle的驅(qū)動(dòng)
public static void registerDriver(Driver driver); //注冊(cè)驅(qū)動(dòng)的意思, 形參是誰(shuí)的驅(qū)動(dòng), 就注冊(cè)誰(shuí).
//Driver類就是MySQL數(shù)據(jù)庫(kù)提供的 驅(qū)動(dòng)類
public class com.mysql.jdbc.Driver implements java.sql.Driver{
}
//記憶: 實(shí)際開發(fā)中, 我們不用上述的方式注冊(cè)驅(qū)動(dòng), 因?yàn)樯鲜鲎?cè)驅(qū)動(dòng)的方式會(huì)導(dǎo)致驅(qū)動(dòng)程序注冊(cè)兩次.
//所以: 我們通過(guò)反射的方式加載 com.mysql.jdbc.Driver類的字節(jié)碼文件, 從而來(lái)自動(dòng) 注冊(cè)驅(qū)動(dòng).
Class.forName("com.mysql.jdbc.Driver"); //驅(qū)動(dòng)類的全路徑
作用二: 獲取連接對(duì)象.
public static Connection getConnection(String url, String username, String password); //獲取連接對(duì)象.
/*
url: 數(shù)據(jù)庫(kù)連接字符串.
格式:
大白話: 連接方式:要操作的DBMS://要操作的數(shù)據(jù)庫(kù)的IP地址或者主機(jī)名:端口號(hào)/要操作的具體的數(shù)據(jù)庫(kù)
專業(yè): 協(xié)議:子協(xié)議:要操作的DBMS://要操作的數(shù)據(jù)庫(kù)的IP地址或者主機(jī)名:端口號(hào)/要操作的具體的數(shù)據(jù)庫(kù)
例如:
jdbc:mysql://127.0.0.1:3306/web04
jdbc:mysql://localhost:3306/web04
如果操作的是本地?cái)?shù)據(jù)庫(kù)(DBMS), 上述的寫法可以優(yōu)化為:
jdbc:mysql:///web04
username: 要操作的數(shù)據(jù)庫(kù)(DBMS)的賬號(hào)
password: 要操作的數(shù)據(jù)庫(kù)(DBMS)的密碼
*/
6. JDBC的API詳解之: Connection(接口)
Connection: 連接對(duì)象
作用一: 獲取可以執(zhí)行SQL語(yǔ)句的對(duì)象. //掌握
public Statement createStatement(); //獲取可以執(zhí)行SQL語(yǔ)句的對(duì)象.
public PreparedStatement prepareStatement(String sql); //獲取可以執(zhí)行SQL語(yǔ)句的對(duì)象, 具有預(yù)編譯功能, 可以解決SQL注入攻擊問(wèn)題.
作用二: 可以進(jìn)行事務(wù)管理.
public void setAutoCommit(boolean flag); //設(shè)置是否開啟事務(wù)的自動(dòng)提交功能, 相當(dāng)于我們昨天講解的: 開啟事務(wù).
public void commit(); //提交事務(wù)
public void rollback(); //事務(wù)回滾
public void setTransactionIsolation(int level); //設(shè)置事務(wù)的隔離級(jí)別
Connection接口中的常量:
public static final int TRANSACTION_NONE = 0;
public static final int TRANSACTION_READ_UNCOMMITTED = 1;
public static final int TRANSACTION_READ_COMMITTED = 2;
public static final int TRANSACTION_REPEATABLE_READ = 4;
public static final int TRANSACTION_SERIALIZABLE = 8;
7. JDBC的API詳解之: Statement(接口)
Statement: 可以操作SQL語(yǔ)句的對(duì)象.
作用一: 執(zhí)行SQL語(yǔ)句. //掌握
public ResultSet executeQuery(String sql); //執(zhí)行查詢語(yǔ)句
public int executeUpdate(String sql); //執(zhí)行更新語(yǔ)句
作用二: 可以執(zhí)行批處理.
//批處理只針對(duì)更新語(yǔ)句有效.
public void addBatch(String sql); //把SQL語(yǔ)句添加到批處理(指令)中.
public int[] executeBatch(); //執(zhí)行批處理(指令)
public void clearBatch(); //清除批出(指令)
users: 添加5條數(shù)據(jù)
orders: 刪除2條數(shù)據(jù), 修改4條數(shù)據(jù)
orderitem: 添加10條數(shù)據(jù), 改3條數(shù)據(jù)
exam: 刪5條數(shù)據(jù)
8. JDBC的API詳解之: ResultSet(接口)
ResultSet: 執(zhí)行查詢語(yǔ)句后的結(jié)果集對(duì)象.
public boolean next(); //判斷結(jié)果集中是否還有數(shù)據(jù). 類似于Iterator#hasNext().
public XXX getXxx(int columnIndex); //根據(jù)列的編號(hào), 獲取該列的信息, Xxx是數(shù)據(jù)類型的意思
public XXX getXxx(String columnName); //根據(jù)列的名字, 獲取該列的信息, Xxx是數(shù)據(jù)類型的意思, 個(gè)人建議用這種方式.
//getInt(), getString(), getObject();
9. JDBC釋放資源的優(yōu)化代碼. //重點(diǎn)掌握.
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try {
//2 alter + enter: 處理異常
Class.forName("com.mysql.jdbc.Driver");
//3
conn = DriverManager.getConnection("jdbc:mysql:///web04", "root", "123");
//4
stat = conn.createStatement();
//5
String sql = "select * from users";
rs = stat.executeQuery(sql);
//6
while (rs.next()) {
int uid = rs.getInt("uid");
String username = rs.getString("username");
String password = rs.getString("password");
System.out.println(uid + "..." + username + "..." + password);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//7
try {
if(rs != null) {
rs.close(); //alt + ↑, 代碼的向上移動(dòng)
rs = null; //GC會(huì)優(yōu)先回收null對(duì)象.
// System.out.println(1/0);
System.out.println("rs 關(guān)了");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (stat != null) {
stat.close();
stat = null;
System.out.println("stat 關(guān)了");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
conn = null;
System.out.println("conn 關(guān)了");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
10. JDBC對(duì)表數(shù)據(jù)的CURD操作
public class Test02_JDBC對(duì)數(shù)據(jù)的CURD操作 {
//alter + enter: 給出建議 Junit4
/**
* JDBC的查
*/
@Test
public void method1() {
System.out.println("JDBC的查, 自己實(shí)現(xiàn)");
}
/**
* JDBC的增
*/
@Test
public void method2() {
Connection conn = null;
Statement stat = null;
try {
//2 alter + enter: 處理異常
Class.forName("com.mysql.jdbc.Driver");
//3
conn = DriverManager.getConnection("jdbc:mysql:///web04", "root", "123");
//4
stat = conn.createStatement();
//5
String sql = "insert Into users values(null,'tianqi','pw567')";
int num = stat.executeUpdate(sql);
//6
if(num > 0) {
System.out.println("添加成功");
} else {
System.out.println("添加失敗");
}
//7
stat.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* JDBC的改
*/
@Test
public void method3() {
Connection conn = null;
Statement stat = null;
try {
//2 alter + enter: 處理異常
Class.forName("com.mysql.jdbc.Driver");
//3
conn = DriverManager.getConnection("jdbc:mysql:///web04", "root", "123");
//4
stat = conn.createStatement();
//5
String sql = "update users set password='777' where uid = 6;";
int num = stat.executeUpdate(sql);
//6
if(num > 0) {
System.out.println("修改成功");
} else {
System.out.println("修改失敗");
}
//7
stat.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* JDBC的刪
*/
@Test
public void method4() {
Connection conn = null;
Statement stat = null;
try {
//2 alter + enter: 處理異常
Class.forName("com.mysql.jdbc.Driver");
//3
conn = DriverManager.getConnection("jdbc:mysql:///web04", "root", "123");
//4
stat = conn.createStatement();
//5
String sql = "delete from users where uid = 6;";
int num = stat.executeUpdate(sql);
//6
if(num > 0) {
System.out.println("刪除成功");
} else {
System.out.println("刪除失敗");
}
//7
stat.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
11. JDBCUtils工具類的抽取
方式一: 普通抽取
public class JDBCUtils {
//1. 構(gòu)造私有.
//2. 注冊(cè)驅(qū)動(dòng), 靜態(tài)代碼塊實(shí)現(xiàn).
//3. 獲取連接對(duì)象.
//4. 釋放資源. try-catch-finally 語(yǔ)句的嵌套實(shí)現(xiàn).
}
此時(shí), 雖然我們已經(jīng)成功的抽取出來(lái)了JDBCUtils工具類, 但是和一個(gè)開發(fā)原則相違背"對(duì)修改關(guān)閉, 對(duì)擴(kuò)展開放".
例如: 如果我們想操作web05這個(gè)數(shù)據(jù)庫(kù)了, 就得修改工具類中url的寫法, 如果我們操作的數(shù)據(jù)庫(kù)的用戶名和密碼
改變了, 我們也得修改工具類中username,password的寫法, 這樣做擴(kuò)展性較差.
于是, 我們就想著如何解決這個(gè)問(wèn)題?
能不能創(chuàng)建一個(gè)文件(配置文件), 里邊記錄的是各項(xiàng)配置信息, 然后由工具類讀取該配置文件的信息即可.
這個(gè)配置文件就是: **.properties
Properties集合類:
概述: 它是一個(gè)雙列集合, 鍵值都是String類型, 它是Hashtable集合的子類.
//Properties集合是唯一可以直接和IO流相結(jié)合使用的集合類.
//它可以直接從流中讀取數(shù)據(jù), 也可以直接寫數(shù)據(jù)到流中.
成員方法:
public void load(InputStream is); //從流中讀取數(shù)據(jù)
public void load(Reader r); //從流中讀取數(shù)據(jù)
public void store(OutputStream os); //寫數(shù)據(jù)到流中
public void store(Writer w); //寫數(shù)據(jù)到流中
public String getProperty(String key); //根據(jù)鍵獲取值
public void setProperty(String key,String value); //設(shè)置鍵值對(duì)
面試題:
Hashtable和HashMap的區(qū)別?
HashMap: 線程不安全, 效率高, 可以存null值和null鍵.
JDK1.2出來(lái)來(lái).
Hashtable: 線程安全, 效率低. 不可以存null值和null鍵.
JDK1.0出來(lái)的.
整個(gè)Java命名規(guī)范是從: JDK1.2開始完善的.
方式二: 結(jié)合配置文件的使用
public class JDBCUtils {
//1. 構(gòu)造私有.
//2. 定義變量, 記錄配置文件的信息.
//3. 讀取配置文件, 并將讀取到的值賦值給變量.
//4. 注冊(cè)驅(qū)動(dòng), 靜態(tài)代碼塊實(shí)現(xiàn).
//5. 獲取連接對(duì)象.
//6. 釋放資源. try-catch-finally 語(yǔ)句的嵌套實(shí)現(xiàn).
}
12. SQL注入攻擊問(wèn)題
概述:
代碼演示SQL注入攻擊問(wèn)題:
解決方案: PreparedStatement接口的預(yù)編譯, 占位符.
今日總結(jié):
1. JDBC的原生態(tài)代碼.
2. JDBC的優(yōu)化釋放資源的代碼
3. Properties的使用
4. 抽取JDBCUtils工具類
5. 解決SQL注入攻擊問(wèn)題