JDBC 完整笔记 + 核心 API 详解(入门到实战)
一、JDBC 概述
什么是 JDBC
JDBC(Java DataBase Connectivity):Java 数据库连接,是 Java 官方定义的一套操作所有关系型数据库的接口(API)。
-
作用:Java 程序统一规范访问 MySQL、Oracle、SQLServer 等数据库,一套代码适配多数据库。
-
本质:
java.sql+javax.sql包下的接口、类、异常。
JDBC 架构
-
Java 应用程序:调用 JDBC 接口
-
JDBC 接口(标准):Sun 定义规范
-
数据库驱动(实现类):数据库厂商实现 JDBC 接口(如
mysql-connector-java) -
数据库服务:MySQL/Oracle 等
核心:面向接口编程,只操作 JDBC 接口,不直接接触驱动实现类。
使用前提
-
导入对应数据库驱动 jar 包
-
MySQL 5.x:
mysql-connector-java-5.1.xx.jar -
MySQL 8.x:
mysql-connector-java-8.0.xx.jar(驱动类、URL 有变化)
-
-
项目中添加依赖(普通项目 / Maven)
Maven 依赖(MySQL8)
xml
sql
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
二、JDBC 核心六大核心 API(重点)
表格
|-------------------|----------|-------------------------------|
| 接口 / 类 | 包 | 作用 |
| Driver | java.sql | 驱动接口,数据库厂商实现 |
| DriverManager | java.sql | 驱动管理类,获取数据库连接 |
| Connection | java.sql | 数据库连接对象,代表 Java 和数据库的通道 |
| Statement | java.sql | SQL 语句执行对象(静态 SQL,有 SQL 注入风险) |
| PreparedStatement | java.sql | 预编译 SQL 对象(推荐,防注入、效率高) |
| ResultSet | java.sql | 结果集对象,封装数据库查询返回的数据 |
三、JDBC 标准执行 7 步(固定流程)
-
加载驱动
-
获取数据库连接 Connection
-
编写 SQL 语句
-
获取 SQL 执行对象(Statement/PreparedStatement)
-
执行 SQL,接收结果
-
处理结果(查询才需要)
-
释放资源(ResultSet → Statement → Connection)
四、逐个 API 详解 + 代码示例
Driver 驱动接口 & 驱动加载
1.1 驱动类全限定名
-
MySQL 5.x:
com.mysql.jdbc.Driver -
MySQL 8.x:
com.mysql.cj.jdbc.Driver(新增cj包,必须写对)
1.2 加载驱动方式
本质:通过反射加载驱动类,自动执行静态代码块完成驱动注册
sql
// 方式1:Class.forName(全类名) 【主流写法】
Class.forName("com.mysql.cj.jdbc.Driver");
// 方式2:new 驱动对象(不推荐,硬编码)
new com.mysql.cj.jdbc.Driver();
补充:MySQL 6.0+ 可省略加载驱动 驱动包内置
META-INF/services/java.sql.Driver文件,自动加载驱动,但企业开发仍建议手动写,兼容性更好。
DriverManager 驱动管理类(获取连接)
2.1 核心静态方法
sql
// 获取数据库连接,返回 Connection 对象
public static Connection getConnection(String url, String user, String password)
2.2 URL 地址格式(关键)
通用格式:jdbc:数据库类型://数据库IP:端口/数据库名?参数
-
MySQL 标准 URL
-
plaintext
sql
jdbc:mysql://localhost:3306/数据库名
-
本机简写(localhost:3306 可省略)
-
plaintext
sql
jdbc:mysql:///数据库名
MySQL8 必须追加时区参数(否则报错 时区异常):
plaintext
sql
jdbc:mysql://localhost:3306/数据库名?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
参数说明:
-
useSSL=false:关闭 SSL 安全连接(本地测试必加) -
serverTimezone=UTC:指定时区,解决时区报错 -
allowPublicKeyRetrieval=true:解决密码认证异常
2.3 代码获取连接
sql
// 数据库信息
String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
String user = "root";
String pwd = "123456";
// 获取连接
Connection conn = DriverManager.getConnection(url, user, pwd);
System.out.println(conn); // 不为null即连接成功
Connection 连接对象(接口)
Connection 是 Java 与数据库的会话通道,生命周期:一次连接。
3.1 核心方法
-
创建 SQL 执行对象
-
java
-
运行
sql
// 创建普通 Statement
Statement createStatement()
// 创建预编译 PreparedStatement(推荐)
PreparedStatement prepareStatement(String sql)
-
事务管理(JDBC 事务核心)
-
java
-
运行
sql
// 关闭自动提交(开启事务),默认 true 自动提交
void setAutoCommit(boolean autoCommit)
// 提交事务
void commit()
// 回滚事务
void rollback()
// 设置事务保存点(进阶)
Savepoint setSavepoint()
- 关闭连接
sql
void close()
3.2 事务使用示例
sql
// 关闭自动提交(开启事务),默认 true 自动提交
void setAutoCommit(boolean autoCommit)
// 提交事务
void commit()
// 回滚事务
void rollback()
// 设置事务保存点(进阶)
Savepoint setSavepoint()
Statement 静态执行对象(了解,不推荐)
4.1 作用
执行静态、固定拼接的 SQL 语句,存在 SQL 注入漏洞。
4.2 核心方法
sql
// 执行 DQL 查询(select),返回结果集 ResultSet
ResultSet executeQuery(String sql)
// 执行 DML(insert/update/delete)、DDL,返回受影响行数
int executeUpdate(String sql)
// 万能方法:可执行任意SQL,返回boolean(是否有结果集)
boolean execute(String sql)
4.3 示例(SQL 注入风险演示)
sql
// 拼接SQL,极易被注入
String name = "张三' or '1'='1";
String sql = "select * from user where name = '"+name+"'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql); // 会查询出所有数据,注入成功
结论:正式开发禁止使用 Statement,一律用
PreparedStatement。
PreparedStatement 预编译执行对象(⭐ 重点推荐)
5.1 特点
-
预编译 SQL:SQL 模板先发送数据库编译,后续只传参数,执行效率高
-
使用?占位符,参数单独设置,彻底防止 SQL 注入
-
支持批量操作
5.2 使用步骤
-
编写 SQL,使用
?作为参数占位符(无单引号) -
通过
Connection创建对象,传入 SQL -
调用
setXxx(占位符索引, 值)给?赋值(索引从 1 开始) -
执行 SQL(无需再传 SQL 语句)
5.3 核心方法
(1)给占位符赋值 setXxx () 系列
根据字段类型选择对应方法:
sql
// 通用格式:set类型(第几个?, 值)
void setInt(int parameterIndex, int x)
void setString(int parameterIndex, String x)
void setDouble(int parameterIndex, double x)
void setDate(int parameterIndex, Date x)
void setObject(int parameterIndex, Object x) // 万能方法
(2)执行 SQL 方法(无参)
sql
// 查询 select → 返回 ResultSet
ResultSet executeQuery()
// 增删改 → 返回受影响行数
int executeUpdate()
// 批量执行(批量增删改)
void addBatch() // 添加批处理任务
int[] executeBatch() // 执行批量任务
void clearBatch() // 清空批处理
5.4 完整增删改查示例
示例 1:查询(DQL)
sql
// 1. 带 ? 占位符的SQL
String sql = "select id,name,age from user where age > ?";
// 2. 创建预编译对象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 3. 给?赋值(索引从1开始)
pstmt.setInt(1, 18);
// 4. 执行查询
ResultSet rs = pstmt.executeQuery();
示例 2:新增(DML)
sql
String sql = "insert into user(name,age) values(?,?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "李四");
pstmt.setInt(2, 20);
int rows = pstmt.executeUpdate(); // 返回影响行数
System.out.println("影响行数:" + rows);
ResultSet 结果集对象(封装查询数据)
ResultSet 用来接收 select 查询返回的表格数据,内部维护一个行指针(游标)。
6.1 核心原理
-
游标默认指向第一行数据之前
-
调用
next()向下移动一行,有数据返回 true,无数据返回 false
6.2 核心方法
1)游标移动方法
sql
boolean next() // 下移一行,常用
boolean previous() // 上移一行(滚动结果集)
boolean first() // 移到第一行
boolean last() // 移到最后一行
void beforeFirst() // 回到初始位置
2)获取列数据 getXxx () 系列
两种取值方式:列索引 / 列名(推荐列名,可读性高)
sql
// 按列索引(从1开始)
int getInt(int columnIndex)
String getString(int columnIndex)
Date getDate(int columnIndex)
// 按列名(推荐)
int getInt(String columnLabel)
String getString(String columnLabel)
Date date = rs.getTimestamp("current_time");
Object getObject(String columnLabel) // 万能获取
6.3 遍历结果集标准写法
sql
// 循环遍历每一行数据
while(rs.next()){
// 取列值
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println(id + " " + name + " " + age);
}
6.4 关闭资源顺序
顺序必须:ResultSet → PreparedStatement → Connection
sql
if(rs != null) try{rs.close();}catch(Exception e){}
if(pstmt != null) try{pstmt.close();}catch(Exception e){}
if(conn != null) try{conn.close();}catch(Exception e){}
五、完整 JDBC 基础模板(可直接复用)
sql
import java.sql.*;
public class JdbcDemo {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 获取连接
String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
String user = "root";
String pwd = "123456";
conn = DriverManager.getConnection(url, user, pwd);
// 3. 编写SQL + 创建预编译对象
String sql = "select * from user";
pstmt = conn.prepareStatement(sql);
// 4. 执行查询,获取结果集
rs = pstmt.executeQuery();
// 5. 遍历结果
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println(id + " " + name);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 6. 释放资源
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}