那個網(wǎng)站做圖片好看電商廣告
一、JDBC介紹
介紹JDBC
JDBC(Java Database Connectivity)是Java中用于連接和操作關(guān)系型數(shù)據(jù)庫的標準API(應(yīng)用程序編程接口)。它是由Sun Microsystems(現(xiàn)在是Oracle的一部分)開發(fā),并隨Java Development Kit (JDK) 一起發(fā)布的。JDBC允許Java應(yīng)用程序與各種關(guān)系型數(shù)據(jù)庫管理系統(tǒng)(DBMS)進行交互,包括但不限于Oracle, MySQL, PostgreSQL, Microsoft SQL Server等。
以下是關(guān)于JDBC的一些關(guān)鍵點:
-
規(guī)范與實現(xiàn):
- JDBC本身是一個規(guī)范,定義了Java應(yīng)用程序如何與數(shù)據(jù)庫通信的接口和協(xié)議。
- 不同數(shù)據(jù)庫供應(yīng)商會提供它們自己的JDBC驅(qū)動程序,這些驅(qū)動程序?qū)崿F(xiàn)了JDBC規(guī)范,使得Java程序可以與特定的數(shù)據(jù)庫進行通信。
-
主要組件:
- Driver(驅(qū)動程序):連接Java應(yīng)用程序和數(shù)據(jù)庫的橋梁,根據(jù)數(shù)據(jù)庫的不同,有不同的驅(qū)動類型。
- Connection(連接):代表與數(shù)據(jù)庫的連接,通過它可以發(fā)送SQL語句給數(shù)據(jù)庫。
- Statement(語句):用于執(zhí)行SQL語句的對象,有
Statement
、PreparedStatement
和CallableStatement
三種。 - ResultSet(結(jié)果集):存儲SQL查詢結(jié)果的對象,可以像迭代器一樣遍歷查詢結(jié)果。
-
使用流程:
- 加載JDBC驅(qū)動程序。
- 建立到數(shù)據(jù)庫的連接。
- 創(chuàng)建
Statement
或PreparedStatement
對象。 - 執(zhí)行SQL語句。
- 處理
ResultSet
中的結(jié)果(如果是查詢語句)。 - 關(guān)閉
ResultSet
、Statement
和Connection
。
-
版本演進:
- JDBC自從1997年隨JDK 1.1發(fā)布以來,經(jīng)歷了多個版本的改進,增加了更多功能,如批處理、存儲過程支持、事務(wù)控制等。
-
優(yōu)點:
- 提供數(shù)據(jù)庫無關(guān)性,即相同的Java代碼可以用于不同的數(shù)據(jù)庫,只需更換對應(yīng)的JDBC驅(qū)動即可。
- 支持多種數(shù)據(jù)庫,增強了應(yīng)用程序的可移植性和靈活性。
-
缺點:
- 相對于其他更高層次的持久層框架(如Hibernate或JPA),JDBC需要更多的手動編碼和資源管理。
JDBC是Java開發(fā)者進行數(shù)據(jù)庫操作的基礎(chǔ),了解和掌握JDBC是進行Java企業(yè)級應(yīng)用開發(fā)的重要技能之一。
二、Statement 和 PreparedStatement
Statement 和 PreparedStatement 的區(qū)別
Statement
和 PreparedStatement
都是 Java 中用于執(zhí)行 SQL 語句的接口,它們屬于 JDBC (Java Database Connectivity) API 的一部分。盡管它們有相似的功能,但在性能、安全性和可維護性方面存在顯著差異。
Statement
- 動態(tài) SQL:
Statement
用于執(zhí)行靜態(tài) SQL 語句,即 SQL 語句是在運行時通過字符串構(gòu)建的。 - 編譯: 每次使用
Statement
執(zhí)行 SQL 語句時,數(shù)據(jù)庫都需要重新解析和編譯 SQL 語句。 - 性能: 如果同一個 SQL 語句需要多次執(zhí)行,每次執(zhí)行都會有一定的編譯開銷。
- 安全性: 使用
Statement
容易受到 SQL 注入攻擊,因為字符串拼接時可能沒有正確轉(zhuǎn)義特殊字符。 - 參數(shù)化: 不支持參數(shù)化查詢,所有參數(shù)必須在 SQL 字符串中硬編碼。
PreparedStatement
- 預(yù)編譯 SQL:
PreparedStatement
允許你預(yù)編譯 SQL 語句,這意味著數(shù)據(jù)庫只需要編譯一次 SQL 語句,然后可以多次執(zhí)行,這提高了性能。 - 參數(shù)化: 支持參數(shù)化查詢,使用占位符(通常是問號
?
)來代替具體的值。在執(zhí)行時,具體的值會被傳入這些占位符位置。 - 安全性: 參數(shù)化查詢可以防止 SQL 注入攻擊,因為數(shù)據(jù)庫驅(qū)動器會自動處理參數(shù)的轉(zhuǎn)義和類型轉(zhuǎn)換。
- 可維護性: 由于使用了參數(shù)化查詢,代碼更易于閱讀和維護。
- 批處理:
PreparedStatement
支持批處理,可以一次發(fā)送多個 SQL 語句給數(shù)據(jù)庫,進一步提升性能。
總結(jié)來說,PreparedStatement
相對于 Statement
提供了更好的性能、安全性和可維護性,尤其是在需要多次執(zhí)行相同 SQL 語句的情況下。因此,在現(xiàn)代應(yīng)用中,PreparedStatement
被廣泛推薦使用。
預(yù)編譯 SQL 語句
預(yù)編譯 SQL 語句,這意味著數(shù)據(jù)庫只需要編譯一次 SQL 語句,什么意思?
預(yù)編譯 SQL 語句的概念意味著將 SQL 查詢的結(jié)構(gòu)與實際的數(shù)據(jù)值分離處理。當(dāng)使用 PreparedStatement
時,SQL 語句的結(jié)構(gòu)被提前發(fā)送到數(shù)據(jù)庫并進行解析和編譯,這個過程稱為預(yù)編譯。
具體來說,當(dāng)你使用 PreparedStatement
創(chuàng)建一個 SQL 語句,比如:
String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
PreparedStatement pstmt = connection.prepareStatement(sql);
這里,SQL 語句 "INSERT INTO users (name, age) VALUES (?, ?)"
被發(fā)送到數(shù)據(jù)庫。數(shù)據(jù)庫接收到這個 SQL 語句后,會進行以下操作:
- 語法分析:檢查 SQL 語句的語法是否正確。
- 解析:理解 SQL 語句的意圖,如識別表名、列名等。
- 編譯:生成執(zhí)行計劃,決定如何最有效地執(zhí)行查詢。
這些步驟通常比直接執(zhí)行 SQL 語句要耗時得多。但是,一旦 SQL 語句被預(yù)編譯,其執(zhí)行計劃就被緩存起來。之后,當(dāng)你準備并設(shè)置參數(shù)值時:
pstmt.setString(1, "John Doe");
pstmt.setInt(2, 30);
pstmt.executeUpdate();
再次執(zhí)行相同的預(yù)編譯 SQL 語句時,數(shù)據(jù)庫不需要重復(fù)上述的解析和編譯步驟,而是直接使用已有的執(zhí)行計劃,這大大加快了 SQL 語句的執(zhí)行速度,特別是在需要多次執(zhí)行相同 SQL 結(jié)構(gòu)但不同數(shù)據(jù)值的場景下。
簡而言之,預(yù)編譯 SQL 語句允許你將 SQL 結(jié)構(gòu)的解析和編譯與實際數(shù)據(jù)的執(zhí)行分開,從而提高執(zhí)行效率和應(yīng)用程序的性能。
三、JDBC-核心API
JDBC(Java Database Connectivity)是 Java 中用于與各種數(shù)據(jù)庫通信的標準 API。它提供了與關(guān)系型數(shù)據(jù)庫交互的統(tǒng)一接口,使得 Java 應(yīng)用程序能夠訪問任何支持 JDBC 的數(shù)據(jù)庫。JDBC 核心 API 主要由以下幾個關(guān)鍵組件組成:
-
DriverManager 類:
- 這是 JDBC 的入口點,負責(zé)加載 JDBC 驅(qū)動并創(chuàng)建
Connection
對象。DriverManager
提供了諸如getConnection(String url)
方法來建立與數(shù)據(jù)庫的連接。
- 這是 JDBC 的入口點,負責(zé)加載 JDBC 驅(qū)動并創(chuàng)建
-
Connection 接口:
Connection
是與數(shù)據(jù)庫的連接。通過Connection
對象,你可以創(chuàng)建Statement
或PreparedStatement
來執(zhí)行 SQL 語句。Connection
還可以配置事務(wù)行為,如自動提交模式。
-
Statement 接口:
Statement
用于執(zhí)行簡單的 SQL 語句。例如,executeQuery(String sql)
方法用于執(zhí)行 SELECT 語句并返回ResultSet
對象;executeUpdate(String sql)
用于執(zhí)行 INSERT, UPDATE 和 DELETE 等語句。
-
PreparedStatement 接口:
PreparedStatement
是Statement
的子接口,用于預(yù)編譯 SQL 語句。它可以接受參數(shù)占位符(通常是問號?
),然后在執(zhí)行前將具體的參數(shù)值傳入。這有助于防止 SQL 注入攻擊,并且提高了 SQL 語句的執(zhí)行效率。
-
CallableStatement 接口:
CallableStatement
同樣是PreparedStatement
的子接口,專門用于調(diào)用數(shù)據(jù)庫存儲過程或函數(shù)。它支持 IN, OUT 和 INOUT 參數(shù)。
-
ResultSet 接口:
ResultSet
表示執(zhí)行 SELECT 語句的結(jié)果集。它提供了一系列方法來遍歷和檢索結(jié)果集中的數(shù)據(jù),如next()
,getString(int columnIndex)
,getInt(int columnIndex)
等。
-
DatabaseMetaData 接口:
DatabaseMetaData
提供了有關(guān)數(shù)據(jù)庫的信息,包括表、視圖、索引、數(shù)據(jù)庫產(chǎn)品名稱、版本等元數(shù)據(jù)。
-
SQLException 類:
- 當(dāng) JDBC 操作出錯時,會拋出
SQLException
。這是所有 JDBC 錯誤的基類,包含了錯誤碼和錯誤消息,幫助開發(fā)者診斷問題。
- 當(dāng) JDBC 操作出錯時,會拋出
為了使用 JDBC,你需要一個合適的 JDBC 驅(qū)動,該驅(qū)動實現(xiàn)了上述接口。不同的數(shù)據(jù)庫廠商提供了各自的 JDBC 驅(qū)動,如 Oracle 的 ojdbc.jar,MySQL 的 mysql-connector-java.jar 等。
使用 JDBC 的基本流程通常包括:
- 加載 JDBC 驅(qū)動。
- 建立數(shù)據(jù)庫連接。
- 創(chuàng)建
Statement
或PreparedStatement
。 - 執(zhí)行 SQL 語句。
- 處理結(jié)果(如果是查詢的話)。
- 關(guān)閉資源(
ResultSet
,Statement
,Connection
)。
JDBC 是 Java 開發(fā)者與數(shù)據(jù)庫交互的基礎(chǔ),掌握其核心 API 對于開發(fā)基于數(shù)據(jù)庫的應(yīng)用程序至關(guān)重要。
四、代碼示例
請?zhí)峁┮粋€完整的jdbc查詢代碼示例
當(dāng)然,下面是一個使用 JDBC 進行數(shù)據(jù)庫查詢的完整代碼示例。這個例子假設(shè)你正在使用 MySQL 數(shù)據(jù)庫,并且你想要查詢一個名為 Employees
的表,該表包含 id
, name
, 和 age
字段。以下是查詢這些字段的示例代碼:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class EmployeeAgeQuery {public static void main(String[] args) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {// 加載數(shù)據(jù)庫驅(qū)動,可省略// Class.forName("com.mysql.cj.jdbc.Driver");// 建立數(shù)據(jù)庫連接String url = "jdbc:mysql://localhost:3306/your_database_name";String user = "your_username";String password = "your_password";connection = DriverManager.getConnection(url, user, password);// 創(chuàng)建 PreparedStatement 對象,注意使用參數(shù)占位符 ?String selectSql = "SELECT id, name, age FROM Employees WHERE age < ?";preparedStatement = connection.prepareStatement(selectSql);// 設(shè)置參數(shù)值preparedStatement.setInt(1, 28); // 將第一個問號替換為28// 執(zhí)行查詢resultSet = preparedStatement.executeQuery();// 處理結(jié)果集while (resultSet.next()) {int employeeId = resultSet.getInt("id");String employeeName = resultSet.getString("name");int employeeAge = resultSet.getInt("age");System.out.println("ID: " + employeeId + ", Name: " + employeeName + ", Age: " + employeeAge);}} catch (ClassNotFoundException e) {// 處理找不到驅(qū)動的情況e.printStackTrace();} catch (SQLException e) {// 處理 SQL 異常e.printStackTrace();} finally {// 關(guān)閉資源try {if (resultSet != null) resultSet.close();if (preparedStatement != null) preparedStatement.close();if (connection != null) connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}
請注意,你需要將 your_database_name
、your_username
和 your_password
替換為你的數(shù)據(jù)庫名稱、用戶名和密碼。此外,確保你的 MySQL 驅(qū)動程序 com.mysql.cj.jdbc.Driver
已經(jīng)添加到了項目類路徑中。
此代碼示例展示了如何加載 JDBC 驅(qū)動,建立數(shù)據(jù)庫連接,執(zhí)行 SQL 查詢,處理結(jié)果集,以及最后關(guān)閉所有的數(shù)據(jù)庫資源以避免內(nèi)存泄漏。