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.jarMySQL 8.x:
mysql-connector-java-8.0.xx.jar(驱动类、URL 有变化)
项目中添加依赖(普通项目 / Maven)
Maven 依赖(MySQL8)
xml
<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.DriverMySQL 8.x:
com.mysql.cj.jdbc.Driver(新增cj包,必须写对)
1.2 加载驱动方式
本质:通过反射加载驱动类,自动执行静态代码块完成驱动注册
// 方式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 核心静态方法
// 获取数据库连接,返回 Connection 对象 public static Connection getConnection(String url, String user, String password)2.2 URL 地址格式(关键)
通用格式:jdbc:数据库类型://数据库IP:端口/数据库名?参数
MySQL 标准 URL
plaintext
jdbc:mysql://localhost:3306/数据库名本机简写(localhost:3306 可省略)
plaintext
jdbc:mysql:///数据库名MySQL8 必须追加时区参数(否则报错时区异常):
plaintext
jdbc:mysql://localhost:3306/数据库名?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true参数说明:
useSSL=false:关闭 SSL 安全连接(本地测试必加)serverTimezone=UTC:指定时区,解决时区报错allowPublicKeyRetrieval=true:解决密码认证异常
2.3 代码获取连接
// 数据库信息 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
运行
// 创建普通 Statement Statement createStatement() // 创建预编译 PreparedStatement(推荐) PreparedStatement prepareStatement(String sql)事务管理(JDBC 事务核心)
java
运行
// 关闭自动提交(开启事务),默认 true 自动提交 void setAutoCommit(boolean autoCommit) // 提交事务 void commit() // 回滚事务 void rollback() // 设置事务保存点(进阶) Savepoint setSavepoint()关闭连接
void close()3.2 事务使用示例
// 关闭自动提交(开启事务),默认 true 自动提交 void setAutoCommit(boolean autoCommit) // 提交事务 void commit() // 回滚事务 void rollback() // 设置事务保存点(进阶) Savepoint setSavepoint()Statement 静态执行对象(了解,不推荐)
4.1 作用
执行静态、固定拼接的 SQL 语句,存在 SQL 注入漏洞。
4.2 核心方法
// 执行 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,极易被注入 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 () 系列
根据字段类型选择对应方法:
// 通用格式: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 方法(无参)
// 查询 select → 返回 ResultSet ResultSet executeQuery() // 增删改 → 返回受影响行数 int executeUpdate() // 批量执行(批量增删改) void addBatch() // 添加批处理任务 int[] executeBatch() // 执行批量任务 void clearBatch() // 清空批处理5.4 完整增删改查示例
示例 1:查询(DQL)
// 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)
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)游标移动方法
boolean next() // 下移一行,常用 boolean previous() // 上移一行(滚动结果集) boolean first() // 移到第一行 boolean last() // 移到最后一行 void beforeFirst() // 回到初始位置2)获取列数据 getXxx () 系列
两种取值方式:列索引 / 列名(推荐列名,可读性高)
// 按列索引(从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 遍历结果集标准写法
// 循环遍历每一行数据 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
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 基础模板(可直接复用)
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(); } } } }