JDBC
一、JDBC概述
什么是JDBC?

JDBC 是使用 Java 語言操作關系型資料庫的一套 API,這套 API 是交由不同的資料庫廠商實作的,我們利用 JDBC 撰寫操作資料庫的代碼,真正執行的是各個資料庫的實作類(驅動),
全稱:(Java DataBase Connectivity)Java 資料庫連接,
JDBC的好處
- 面向介面編程,屏蔽實作上的差異,
- 一套 Java 代碼操作不同資料庫,、
二、使用JDBC
環境配置
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
編碼
步驟
- 引入驅動并注冊
- 獲取連接
- 定義SQL
- 獲取執行SQL物件
- 執行SQL
- 處理回傳結果
- 釋放資源
代碼實作
public static void demo(){
Connection conn = null;
Statement state = null;
try {
// 1.注冊驅動
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.獲取連接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
// 3.定義SQL
String sql = "select * from user";
// 4.獲取Statement物件
state = conn.createStatement();
// 5.執行SQL
ResultSet resultSet = state.executeQuery(sql);
// 6.處理回傳結果
System.out.println(resultSet);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 7.關閉資源
if (state != null) {
try {
state.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
注意
-
最晚獲得的資源最先關閉,
-
Mysql8之前的驅動類全類名為com.mysql.jdbc.Driver,Mysql8之后則為com.mysql.cj.jdbc.Driver,
三、JDBC API
DriverManager
作用
- 注冊驅動
- 獲取資料庫連接
這兩個作用對應著兩個方法:
| 方法 | 作用 |
|---|---|
| getConnection(String url, String user, String password) | 通過給定的URL與資料庫建立連接,并回傳連接物件 |
| registerDriver(Driver driver) | 注冊給定的驅動 Driver |
Mysql 驅動底層通過靜態代碼塊呼叫了DriverManager的registerDriver方法,所以我們不必去顯式的進行驅動的注冊,它已經幫我們注冊好了,
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
注意
如果匯入 MySQL5 之后的驅動 jar包,可以不用寫 Class.forName("com.mysql.cj.jdbc.Driver");,Driver 會自動讀取 java.sql.Driver檔案中的驅動類全限定名,進行驅動的注冊,

Connection
作用
- 獲取執行SQl的物件
- 管理事務
執行SQL的物件
-
Statement普通的執行物件,將獲得的欄位拼接在SQl陳述句上,然后在執行編譯,有SQl注入攻擊的風險,
-
PerparedStatement對SQL進行
預編譯的執行物件,先對SQl陳述句進行編譯,再用欄位將?替換掉, -
CallableStatement執行存盤程序的物件,
事務管理
| 方法 | 說明 |
|---|---|
| setAutoCommit(boolean) | 開啟事務,true:自動提交事務,false:開啟手動提交事務 |
| commit() | 提交事務 |
| rollback() | 回滾事務 |
try {
// 開啟事務
conn.setAutoCommit(false);
// 執行操作一
int i = state.executeUpdate(sql1);
System.out.println(i);
// 制造例外
int j = 1/0;
// 執行操作二
int i1 = state.executeUpdate(sql2);
System.out.println(i1);
// 提交事務
conn.commit();
} catch (Exception e) {
// 事務回滾
conn.rollback();
e.printStackTrace();
}
Statement
作用
執行 sql 陳述句,
方法
| 方法 | 說明 |
|---|---|
int executeUpdate(String sql) |
執行給定的SQL陳述句,這可能是 INSERT , UPDATE ,或 DELETE陳述句,或者不回傳任何內容,如SQL DDL陳述句的SQL陳述句,并回傳受影響的行數, |
ResultSet executeQuery(String sql) |
執行給定的SQL陳述句,該陳述句回傳單個 ResultSet物件, |
ResultSet
作用
封裝了查詢陳述句的執行結果,Statement 或者 PreparedStatement 通過執行 executeQuery 方法回傳 ResultSet 物件,
方法
| 方法 | 說明 |
|---|---|
| getXxx() | 獲取每行中各個資料,可以傳入 列號(從1開始) 或者 列名 |
| next() | 向下移動指標,判斷該行是否有資料, |

// 6.處理回傳結果
while (resultSet.next()) {
String name = resultSet.getString("name");
System.out.println(name);
String password = resultSet.getString(3);
System.out.println(password);
}
PerparedStatement
作用
執行 sql 陳述句,但是它會對 SQl 陳述句進行預編譯,可以防止 SQl 注入攻擊,并且 PreparedStatement 繼承自 Statement ,
SQl注入
在編譯之前利用 SQl 陳述句的拼接,輸入特殊字串修改定義好的 SQL 陳述句,改變 SQL 陳述句的語意,
一個簡單的 SQL 注入演示:
(比如是有一個用戶登錄的場景,在 DAO 層中進行資料庫操作)
String sql = "select * from user where username='"+admin+"' and password='"+'or'1'='1+"'";
用戶密碼一看就不正經,但是可以看一下拼接好的 SQL 陳述句是怎樣的:
select * from user where username='admin' and password=''or'1'='1'
password 變成了空字串,在 SQL 陳述句的尾部 拼接了 or '1'='1' ,username 和 password 查詢為false,但是接著又 or 一個恒等式,整體結果就變成了 true,將會查詢出所有結果,
預編譯
PreparedStatement 的使用步驟:
// 3.定義SQL
String sql = "select * from user where name=? and password=?";
// 4.獲取PreparedStatement物件
PreparedStatement statement = conn.prepareStatement(sql);
// 4.5替換占位符
statement.setString(1,"黑夫");
statement.setString(2,"123");
// 5.執行SQL
ResultSet resultSet = statement.executeQuery();
在定義 SQL 陳述句時,SQL 中未知欄位使用 ? 進行占位,
可以看到在獲取 PreparedStatement 物件的同時,就需要將 SQL 傳入,這時會將 SQL 陳述句發送給 mysql 服務器,進行檢查語法、編譯等,
為什么能達到防止 SQL 注入的效果?
SQL 陳述句在執行之前已經進行了編譯,它的結構已經被固定下來,當運行時動態地把引數傳給 PreprareStatement 時,即使引數里有敏感字符如 or '1=1'資料庫會將它作為一個引數一個欄位的屬性值來處理而不會作為一個 SQL 指令,而且 PreparedStatement 在用具體欄位替換占位符時,會對特殊字符進行轉義,比如單引號 ' 會轉義為 \',如此,可以有效的防止 SQL 注入,
可以在 url 后面加上命令開啟預編譯:useServerPrepStmts=true,不寫這句,仍會對特殊字符進行轉義,
jdbc:mysql://localhost:3306/test?useSSL=false&useServerPrepStmts=true
useSSL=false 表示不進行安全連接,
預編譯的好處
-
防止 SQL 注入
-
一次編譯、多次運行,省去了決議優化等程序
在執行 SQL 時,很多 SQL 陳述句都是結構相同的,只是個別欄位不同,如果對每一條 SQL 進行編譯,那么運行速度將大大降低,預編譯時會將編譯過后的SQL陳述句進行快取,當有結構相同的 SQL 陳述句需要執行時,只需用屬性值替換掉占位符即可,不需要重新
詞法語意決議、陳述句優化、制定執行計劃、編譯等,從而提高效率,
關于更多 PreparedStatement 的了解,看這篇博文:
預編譯陳述句(Prepared Statements)介紹,以MySQL為例
四、資料庫連接池
簡介
資料庫連接池是負責分配、管理和釋放資料庫連接的容器,它允許應用程式重復使用一個現有的資料庫連接,而不是再重新建立一個,
對于多用戶的應用,如果為每一個用戶都創建一個資料庫連接,毫無疑問是對資源的浪費,同時也浪費時間,我們應當在系統加載的時候就將資料庫資源創建好,不推薦運行時再去開啟資源,做到對資源的統一管理,從而避免資源浪費,提升回應速度,
使用
SUN 公司提供了資料庫連接池的標準介面 DataSource 由第三方組織進行實作,
推薦使用 Druid 資料庫連接池技術,
環境搭建
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.11</version>
</dependency>
在resources目錄下新建 druid.properties 組態檔
driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/test
username = root
password = root
# 初始化連接數
initialSize = 5
# 最大連接數
maxActive = 10
# 最大等待時間
maxWait = 3000
maxWait 表示如果連接池中沒有空閑連接的最大等待時間,超過時間則會拋出例外,
更多配置參考:Configuration reference
獲取連接
// 1.加載組態檔
Properties properties = new Properties();
properties.load(ClassLoader.getSystemResourceAsStream("druid.properties"));
// 2.獲取連接
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
conn = dataSource.getConnection();
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/502956.html
標籤:其他
下一篇:MySQL InnoDB索引原理
