Java 作為一種廣泛應(yīng)用的編程語言,在企業(yè)級(jí)應(yīng)用開發(fā)中扮演著重要角色。而數(shù)據(jù)庫作為數(shù)據(jù)存儲(chǔ)和管理的核心,與 Java 應(yīng)用的交互至關(guān)重要。小編將詳細(xì)介紹 Java 如何連接數(shù)據(jù)庫、查詢數(shù)據(jù),以及如何調(diào)用 MySQL 存儲(chǔ)過程,幫助開發(fā)者構(gòu)建高效、可靠的數(shù)據(jù)庫應(yīng)用。
一、Java 連接數(shù)據(jù)庫:JDBC 的力量
Java 通過 JDBC (Java Database Connectivity) API 來連接和操作各種數(shù)據(jù)庫。JDBC 提供了一組接口和類,允許 Java 程序與數(shù)據(jù)庫進(jìn)行通信,執(zhí)行 SQL 語句,并處理結(jié)果集。
1. JDBC 連接數(shù)據(jù)庫的步驟:
加載數(shù)據(jù)庫驅(qū)動(dòng): 首先,需要加載對(duì)應(yīng)數(shù)據(jù)庫的 JDBC 驅(qū)動(dòng)程序。例如,連接 MySQL 數(shù)據(jù)庫,需要加載 MySQL Connector/J 驅(qū)動(dòng)。可以使用 Class.forName() 方法加載驅(qū)動(dòng)。
try {
Class.forName("com.mysql.cj.jdbc.Driver"); // MySQL 8.0+
// Class.forName("com.mysql.jdbc.Driver"); // MySQL 5.x
} catch (ClassNotFoundException e) {
System.err.println("MySQL JDBC Driver not found!");
e.printStackTrace();
return; // 或拋出異常
}
建立數(shù)據(jù)庫連接: 使用 DriverManager.getConnection() 方法建立與數(shù)據(jù)庫的連接。需要提供數(shù)據(jù)庫 URL、用戶名和密碼。
String url = "jdbc:mysql://localhost:3306/mydatabase?serverTimezone=UTC"; // 數(shù)據(jù)庫 URL
String user = "myuser"; // 數(shù)據(jù)庫用戶名
String password = "mypassword"; // 數(shù)據(jù)庫密碼
Connection connection = null;
try {
connection = DriverManager.getConnection(url, user, password);
System.out.println("Connected to database!");
} catch (SQLException e) {
System.err.println("Failed to connect to database!");
e.printStackTrace();
return; // 或拋出異常
}
創(chuàng)建 Statement 或 PreparedStatement 對(duì)象: Statement 用于執(zhí)行靜態(tài) SQL 語句,而 PreparedStatement 用于執(zhí)行預(yù)編譯的 SQL 語句,可以防止 SQL 注入攻擊,并提高性能。
Statement statement = null;
PreparedStatement preparedStatement = null;
try {
statement = connection.createStatement();
String sql = "SELECT * FROM users";
ResultSet resultSet = statement.executeQuery(sql);
// 處理結(jié)果集
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String email = resultSet.getString("email");
System.out.println("ID: " + id + ", Name: " + name + ", Email: " + email);
}
// 使用 PreparedStatement
String sqlPrepared = "SELECT * FROM users WHERE id = ?";
preparedStatement = connection.prepareStatement(sqlPrepared);
preparedStatement.setInt(1, 1); // 設(shè)置參數(shù)
ResultSet resultSetPrepared = preparedStatement.executeQuery();
// 處理結(jié)果集
while (resultSetPrepared.next()) {
int id = resultSetPrepared.getInt("id");
String name = resultSetPrepared.getString("name");
String email = resultSetPrepared.getString("email");
System.out.println("ID: " + id + ", Name: " + name + ", Email: " + email);
}
} catch (SQLException e) {
System.err.println("Failed to execute SQL query!");
e.printStackTrace();
} finally {
// 關(guān)閉資源
try {
if (statement != null) statement.close();
if (preparedStatement != null) preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
執(zhí)行 SQL 語句: 使用 executeQuery() 方法執(zhí)行 SELECT 語句,返回 ResultSet 對(duì)象。使用 executeUpdate() 方法執(zhí)行 INSERT、UPDATE、DELETE 語句,返回受影響的行數(shù)。
處理結(jié)果集 (ResultSet): ResultSet 對(duì)象包含查詢結(jié)果??梢允褂?next() 方法遍歷結(jié)果集,使用 getInt()、getString() 等方法獲取每一列的值。
關(guān)閉連接和資源: 在使用完數(shù)據(jù)庫連接后,務(wù)必關(guān)閉連接和相關(guān)的資源,如 Statement、PreparedStatement 和 ResultSet 對(duì)象,以釋放資源并避免連接泄漏。
finally {
try {
if (resultSet != null) resultSet.close();
if (statement != null) statement.close();
if (preparedStatement != null) preparedStatement.close();
if (connection != null) connection.close();
System.out.println("Connection closed.");
} catch (SQLException e) {
e.printStackTrace();
}
}
2. 數(shù)據(jù)庫連接池:提高性能
頻繁地建立和關(guān)閉數(shù)據(jù)庫連接會(huì)消耗大量資源。為了提高性能,可以使用數(shù)據(jù)庫連接池。連接池維護(hù)一組數(shù)據(jù)庫連接,當(dāng)需要連接時(shí),從連接池中獲取一個(gè)連接,使用完后歸還給連接池,避免了重復(fù)創(chuàng)建和銷毀連接的開銷。
常用的 Java 連接池有:
HikariCP: 高性能、輕量級(jí)的連接池。
Apache Commons DBCP: 穩(wěn)定、成熟的連接池。
C3P0: 功能豐富的連接池。
二、Java 調(diào)用 MySQL 存儲(chǔ)過程
存儲(chǔ)過程是在數(shù)據(jù)庫服務(wù)器上預(yù)先編譯好的 SQL 語句集合,可以接受參數(shù),執(zhí)行復(fù)雜的業(yè)務(wù)邏輯,并返回結(jié)果。調(diào)用存儲(chǔ)過程可以提高性能,減少網(wǎng)絡(luò)傳輸,并增強(qiáng)安全性。
1. 創(chuàng)建 MySQL 存儲(chǔ)過程:
DELIMITER //
CREATE PROCEDURE GetUserById(IN userId INT, OUT userName VARCHAR(255), OUT userEmail VARCHAR(255))
BEGIN
SELECT name, email INTO userName, userEmail FROM users WHERE id = userId;
END //
DELIMITER ;
這個(gè)存儲(chǔ)過程 GetUserById 接受一個(gè)輸入?yún)?shù) userId,并返回兩個(gè)輸出參數(shù) userName 和 userEmail。
2. Java 調(diào)用存儲(chǔ)過程的步驟:
創(chuàng)建 CallableStatement 對(duì)象: 使用 Connection.prepareCall() 方法創(chuàng)建 CallableStatement 對(duì)象,指定存儲(chǔ)過程的名稱。
CallableStatement callableStatement = null;
try {
String sql = "{call GetUserById(?, ?, ?)}";
callableStatement = connection.prepareCall(sql);
} catch (SQLException e) {
System.err.println("Failed to create CallableStatement!");
e.printStackTrace();
return; // 或拋出異常
}
注冊(cè)輸出參數(shù): 使用 registerOutParameter() 方法注冊(cè)存儲(chǔ)過程的輸出參數(shù),指定參數(shù)的位置和數(shù)據(jù)類型。
try {
callableStatement.setInt(1, 1); // 設(shè)置輸入?yún)?shù) userId
callableStatement.registerOutParameter(2, Types.VARCHAR); // 注冊(cè)輸出參數(shù) userName
callableStatement.registerOutParameter(3, Types.VARCHAR); // 注冊(cè)輸出參數(shù) userEmail
} catch (SQLException e) {
System.err.println("Failed to register output parameters!");
e.printStackTrace();
return; // 或拋出異常
}
執(zhí)行存儲(chǔ)過程: 使用 execute() 方法執(zhí)行存儲(chǔ)過程。
try {
callableStatement.execute();
} catch (SQLException e) {
System.err.println("Failed to execute stored procedure!");
e.printStackTrace();
return; // 或拋出異常
}
獲取輸出參數(shù): 使用 getXXX() 方法獲取存儲(chǔ)過程的輸出參數(shù),例如 getString() 獲取字符串類型的參數(shù)。
try {
String userName = callableStatement.getString(2); // 獲取 userName
String userEmail = callableStatement.getString(3); // 獲取 userEmail
System.out.println("User Name: " + userName + ", User Email: " + userEmail);
} catch (SQLException e) {
System.err.println("Failed to get output parameters!");
e.printStackTrace();
} finally {
// 關(guān)閉資源
try {
if (callableStatement != null) callableStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
3. 完整示例代碼:
import java.sql.*;
public class StoredProcedureExample {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/mydatabase?serverTimezone=UTC";
String user = "myuser";
String password = "mypassword";
Connection connection = null;
CallableStatement callableStatement = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection(url, user, password);
String sql = "{call GetUserById(?, ?, ?)}";
callableStatement = connection.prepareCall(sql);
callableStatement.setInt(1, 1); // 設(shè)置輸入?yún)?shù) userId
callableStatement.registerOutParameter(2, Types.VARCHAR); // 注冊(cè)輸出參數(shù) userName
callableStatement.registerOutParameter(3, Types.VARCHAR); // 注冊(cè)輸出參數(shù) userEmail
callableStatement.execute();
String userName = callableStatement.getString(2); // 獲取 userName
String userEmail = callableStatement.getString(3); // 獲取 userEmail
System.out.println("User Name: " + userName + ", User Email: " + userEmail);
} catch (ClassNotFoundException e) {
System.err.println("MySQL JDBC Driver not found!");
e.printStackTrace();
} catch (SQLException e) {
System.err.println("Failed to connect or execute stored procedure!");
e.printStackTrace();
} finally {
try {
if (callableStatement != null) callableStatement.close();
if (connection != null) connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
小編詳細(xì)介紹了 Java 如何連接數(shù)據(jù)庫、查詢數(shù)據(jù),以及如何調(diào)用 MySQL 存儲(chǔ)過程。掌握這些技術(shù),可以幫助開發(fā)者構(gòu)建高效、可靠的數(shù)據(jù)庫應(yīng)用。在實(shí)際開發(fā)中,需要根據(jù)具體需求選擇合適的連接方式、查詢方式和存儲(chǔ)過程調(diào)用方式,并遵循最佳實(shí)踐,以提高應(yīng)用的性能和安全性。