目录
4. 使用 PreparedStatement 防止 SQL 注入
JDBC(Java Database Connectivity)是 Java 提供的数据库访问技术,它允许 Java 程序通过 SQL 语句与数据库进行交互。通过 JDBC,开发者能够实现常见的数据库操作,如增、删、改、查等。在这篇文章中,我们将深入探讨如何使用 JDBC 连接数据库,并执行各种常见的数据库操作。
一、JDBC 简介
JDBC 是 Java 语言提供的标准接口,允许开发者与各种关系型数据库系统(如 MySQL、Oracle、SQL Server 等)进行交互。JDBC 本质上是一组 Java API,它定义了如何执行 SQL 语句、更新数据、查询结果等操作。
在 JDBC 中,我们主要通过以下几个步骤进行数据库操作:
- 加载数据库驱动:通过
Class.forName()
或使用数据源自动加载数据库驱动。- 建立连接:使用
DriverManager.getConnection()
获取数据库连接。- 执行 SQL 语句:使用
Statement
或PreparedStatement
执行 SQL 语句。- 处理结果集:通过
ResultSet
处理查询结果。- 关闭资源:关闭
Connection
、Statement
和ResultSet
等资源。
二、JDBC 环境准备
1. 添加 JDBC 驱动
首先,确保在你的 Java 项目中添加了适合你所使用数据库的 JDBC 驱动。如果你使用的是 Maven 构建工具,可以在 pom.xml
文件中加入依赖:
对于 MySQL 数据库:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
对于 Oracle 数据库,可能需要下载 .jar
文件并手动添加到项目的 lib
目录中。
2. 创建数据库
假设我们使用 MySQL 数据库,首先在数据库中创建一个简单的表 users
,该表包含 id
、name
和 age
三个字段。你可以通过以下 SQL 语句创建数据库和表:
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
age INT NOT NULL
);
INSERT INTO users (name, age) VALUES ('Alice', 30), ('Bob', 25), ('Charlie', 35);
三、JDBC 编程步骤
1. 加载数据库驱动
在 Java 中连接数据库时,首先需要加载数据库驱动。在 JDBC 中,我们可以通过 Class.forName()
方法加载驱动类。对于 MySQL 数据库,驱动类是 com.mysql.cj.jdbc.Driver
。
try {
Class.forName("com.mysql.cj.jdbc.Driver"); // 加载 MySQL 驱动
System.out.println("数据库驱动加载成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.println("数据库驱动加载失败");
}
2. 获取数据库连接
连接数据库是通过 DriverManager.getConnection()
方法实现的。在获取连接时,我们需要提供数据库的 URL、用户名和密码。连接 URL 的格式通常如下:
jdbc:mysql://localhost:3306/testdb
代码示例:
String url = "jdbc:mysql://localhost:3306/testdb";
String user = "root"; // 数据库用户名
String password = "password"; // 数据库密码
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
System.out.println("数据库连接成功");
} catch (SQLException e) {
e.printStackTrace();
System.out.println("数据库连接失败");
}
3. 创建 Statement 对象并执行 SQL
一旦获得数据库连接,就可以通过 Connection
对象创建 Statement
或 PreparedStatement
来执行 SQL 语句。我们来看一个查询操作的例子,查询 users
表中的所有用户信息:
String query = "SELECT * FROM users";
Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
rs = stmt.executeQuery(query);
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println("ID: " + id + ", Name: " + name + ", Age: " + age);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
4. 使用 PreparedStatement 防止 SQL 注入
PreparedStatement
是 Statement
的一种增强版,它可以提高执行效率并防止 SQL 注入。在执行带参数的 SQL 语句时,应该优先使用 PreparedStatement
。
例如,插入一个新用户的 SQL 语句:
String insertQuery = "INSERT INTO users (name, age) VALUES (?, ?)";
PreparedStatement pstmt = null;
try {
pstmt = conn.prepareStatement(insertQuery);
pstmt.setString(1, "David"); // 设置第一个参数为 "David"
pstmt.setInt(2, 40); // 设置第二个参数为 40
int rowsAffected = pstmt.executeUpdate();
System.out.println("插入成功,受影响的行数:" + rowsAffected);
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
5. 事务管理
在 JDBC 中,可以使用事务来确保多个数据库操作的原子性。默认情况下,JDBC 使用自动提交模式,但你可以禁用自动提交来手动管理事务。以下是一个使用事务的示例:
try {
conn.setAutoCommit(false); // 禁用自动提交
String updateQuery1 = "UPDATE users SET age = 26 WHERE name = 'Bob'";
String updateQuery2 = "UPDATE users SET age = 36 WHERE name = 'Charlie'";
stmt = conn.createStatement();
stmt.executeUpdate(updateQuery1);
stmt.executeUpdate(updateQuery2);
conn.commit(); // 提交事务
System.out.println("事务提交成功");
} catch (SQLException e) {
try {
if (conn != null) {
conn.rollback(); // 回滚事务
System.out.println("事务回滚");
}
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} finally {
try {
if (stmt != null) stmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
6. 异常处理和关闭资源
在 JDBC 编程中,异常处理非常重要,因为数据库操作可能会出现各种问题。我们可以使用 try-catch-finally
块来确保资源得到正确释放。所有的数据库连接、Statement
和 ResultSet
都应该在使用完毕后关闭。
四、完整示例
下面是一个完整的 JDBC 示例程序,包括连接数据库、查询、插入、更新、删除操作:
import java.sql.*;
public class JDBCExample {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/testdb";
String user = "root";
String password = "password";
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(url, user, password);
stmt = conn.createStatement();
// 查询操作
String query = "SELECT * FROM users";
rs = stmt.executeQuery(query);
while (rs.next()) {
System.out.println("ID: " + rs.getInt("id") + ", Name: " + rs.getString("name") + ", Age: " + rs.getInt("age"));
}
// 插入操作
String insertQuery = "INSERT INTO users (name, age) VALUES ('Eve', 28)";
stmt.executeUpdate(insertQuery);
// 更新操作
String updateQuery = "UPDATE users SET age = 29 WHERE name = 'Eve'";
stmt.executeUpdate(updateQuery);
// 删除操作
String deleteQuery = "DELETE FROM users WHERE name = 'Eve'";
stmt.executeUpdate(deleteQuery);
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}