目录
[一、JDBC 核心概念](#一、JDBC 核心概念)
[1. 本质](#1. 本质)
[2. 核心组件(必须掌握)](#2. 核心组件(必须掌握))
[二、实操步骤(以 MySQL 8.0+ 为例)](#二、实操步骤(以 MySQL 8.0+ 为例))
[1. 环境准备](#1. 环境准备)
[2. 基础 CRUD 代码模板](#2. 基础 CRUD 代码模板)
[(2)新增 / 修改 / 删除(INSERT/UPDATE/DELETE)](#(2)新增 / 修改 / 删除(INSERT/UPDATE/DELETE))
[1. 防 SQL 注入](#1. 防 SQL 注入)
[2. 事务管理](#2. 事务管理)
[3. 资源释放](#3. 资源释放)
[4. 连接池优化(生产必备)](#4. 连接池优化(生产必备))
[1. 驱动加载异常(ClassNotFoundException)](#1. 驱动加载异常(ClassNotFoundException))
[2. 时区错误(serverTimezone)](#2. 时区错误(serverTimezone))
[3. 连接被拒绝(Connection refused)](#3. 连接被拒绝(Connection refused))
一、JDBC 核心概念
1. 本质
Java 操作关系型数据库的标准 API(接口集合),由数据库厂商提供驱动实现(如 MySQL 的 mysql-connector-java),屏蔽不同数据库底层差异,实现「一次编码,多库兼容」。
2. 核心组件(必须掌握)
| 组件 | 作用 | 关键细节 |
|---|---|---|
| DriverManager | 驱动管理 + 获取连接 | 加载驱动(MySQL 8.0+ 可省略)、getConnection() 获连接 |
| Connection | 数据库连接会话 | 事务控制(提交 / 回滚)、创建执行对象 |
| PreparedStatement | 预编译 SQL 执行对象(推荐) | 防 SQL 注入、占位符 ? 赋值、性能更优 |
| Statement | 静态 SQL 执行对象 | 无预编译,有注入风险,仅用于简单静态 SQL |
| ResultSet | 查询结果集 | 游标遍历(next())、按列名 / 索引取值 |
二、实操步骤(以 MySQL 8.0+ 为例)
1. 环境准备
- 导入驱动依赖(Maven 示例):
xml
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
<scope>runtime</scope>
</dependency>
-
连接参数配置:
-
URL:
jdbc:mysql://localhost:3306/数据库名?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true -
用户名:
root(默认) -
密码:数据库登录密码
-
2. 基础 CRUD 代码模板
(1)查询操作(SELECT)
java
import java.sql.*;
public class JdbcSelectDemo {
public static void main(String[] args) {
// 1. 声明资源(try-with-resources 可自动关闭)
try (Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC",
"root", "123456");
PreparedStatement pstmt = conn.prepareStatement("SELECT id, name FROM user WHERE age > ?");
ResultSet rs = pstmt.executeQuery()) {
// 2. 占位符赋值(索引从 1 开始)
pstmt.setInt(1, 18);
// 3. 遍历结果集
while (rs.next()) {
int id = rs.getInt("id"); // 按列名取值(推荐)
String name = rs.getString(2); // 按列索引取值(不推荐,易出错)
System.out.println("id: " + id + ", name: " + name);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
(2)新增 / 修改 / 删除(INSERT/UPDATE/DELETE)
java
public class JdbcModifyDemo {
public static void main(String[] args) {
String sql = "INSERT INTO user(name, age) VALUES (?, ?)";
try (Connection conn = DriverManager.getConnection(URL, USER, PWD);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, "张三");
pstmt.setInt(2, 22);
int affectedRows = pstmt.executeUpdate(); // 返回受影响行数
System.out.println("新增成功,影响行数:" + affectedRows);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
三、关键技巧与避坑点
1. 防 SQL 注入
- 错误示例(Statement 拼接 SQL):
java
String name = "admin' OR 1=1 --";
String sql = "SELECT * FROM user WHERE name='" + name + "'";
// 拼接后 SQL:SELECT * FROM user WHERE name='admin' OR 1=1 --'(查询所有数据)
- 正确做法:使用
PreparedStatement占位符,自动转义特殊字符。
2. 事务管理
JDBC 默认自动提交事务,手动控制事务步骤:
java
try (Connection conn = DriverManager.getConnection(URL, USER, PWD)) {
conn.setAutoCommit(false); // 关闭自动提交
// 执行多个 SQL 操作
pstmt1.executeUpdate();
pstmt2.executeUpdate();
conn.commit(); // 全部成功则提交
} catch (SQLException e) {
conn.rollback(); // 异常则回滚
e.printStackTrace();
}
3. 资源释放
-
推荐使用
try-with-resources语法(自动关闭实现AutoCloseable接口的资源),无需手动写finally关闭。 -
手动关闭顺序:
ResultSet → PreparedStatement → Connection(逆序创建顺序)。
4. 连接池优化(生产必备)
-
问题:频繁创建 / 销毁
Connection耗时耗资源。 -
解决方案:使用连接池(HikariCP 性能最优,Spring Boot 默认),示例:
java
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
public class HikariDemo {
public static void main(String[] args) throws SQLException {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(URL);
config.setUsername(USER);
config.setPassword(PWD);
config.setMaximumPoolSize(10); // 最大连接数
HikariDataSource dataSource = new HikariDataSource(config);
Connection conn = dataSource.getConnection(); // 从池获取连接
// 使用后自动归还(conn.close() 不是真正关闭)
}
}
四、常见问题排查
1. 驱动加载异常(ClassNotFoundException)
-
原因:驱动类名错误、Maven 依赖未导入。
-
解决:MySQL 8.0+ 驱动类是
com.mysql.cj.jdbc.Driver(5.x 是com.mysql.jdbc.Driver),确认依赖已引入。
2. 时区错误(serverTimezone)
- 解决方案:URL 中添加
serverTimezone=UTC或serverTimezone=Asia/Shanghai。
3. 连接被拒绝(Connection refused)
- 检查:数据库服务是否启动、端口 3306 是否开放、URL 中主机 / 端口是否正确。
五、进阶拓展
-
通用工具类:封装连接获取、SQL 执行方法,减少重复代码。
-
批处理 :使用
addBatch()+executeBatch()批量插入 / 更新,提升效率。 -
结果集映射 :手动映射
ResultSet到 Java 实体类(或使用 MyBatis 等框架自动映射)。 -
事务隔离级别 :通过
conn.setTransactionIsolation()设置,解决脏读、不可重复读、幻读问题。