JavaWeb从0到1-DAY10-JDBC
JDBC 学习笔记
一、这一章在讲什么
JDBC(Java Database Connectivity)是 Java 提供的统一数据库访问接口。不管底层是 MySQL、Oracle 还是 PostgreSQL,Java 程序都通过同一套 JDBC API 来操作数据库。核心价值是可移植性——换数据库只换驱动 jar 和连接字符串,业务代码不用改。
⚠️定位说明:JDBC 是 Java 操作数据库的底层标准,属于"通用规范"。真正的企业开发不会直接手写 JDBC,而是用 MyBatis、JPA(Hibernate)这类封装好的框架——它们底层调的依然是 JDBC。学 JDBC 的目的是理解原理,知道框架在背后做了什么。
二、核心概念
JDBC 是什么
- 一套 Java 标准库中的接口(
java.sql包) - 定义了 Java 程序和数据库之间的"通话规范"
- 各数据库厂商提供各自的驱动实现(如 MySQL 的
mysql-connector-java.jar)
数据库连接(Connection)
- 连接就是 Java 程序和数据库之间建立的一条"通话线路"
- 没有连接,SQL 发不出去,结果也收不回来
- 类比:打电话——拨号(getConnection)→ 通话(执行 SQL)→ 挂断(close)
通信协议
- JDBC 本身是 API 层,不定义通信协议
- 底层协议由各数据库自行定义:MySQL 用私有 TCP 协议(端口 3306),PostgreSQL 用私有 TCP 协议(端口 5432)
- JDBC 驱动负责把 API 调用翻译成数据库能懂的协议
PreparedStatement vs Statement
| Statement | PreparedStatement | |
|---|---|---|
| SQL 拼接 | 字符串拼接,易出错 | ?占位符,清晰安全 |
| SQL 注入 | ❌ 有风险 | ✅ 免疫 |
| 预编译 | 每次都要编译 | 一次编译,多次复用 |
| 结论 | 几乎不用 | 永远首选 |
SQL 注入
- 攻击者在前端输入框中写入 SQL 片段(如
' OR '1'='1) - 如果用 Statement 直接拼接,恶意 SQL 会被数据库当作命令执行
- PreparedStatement 的占位符机制 + 字符转义:你输入的就是纯字符,不会被当成命令
JDBC 编程六步
① 注册驱动 → ② 获取连接 → ③ 创建Statement → ④ 执行SQL → ⑤ 处理结果集 → ⑥ 释放资源- 顺序不能换:必须先有连接才有 Statement,先执行 SQL 才有 ResultSet
- 关闭顺序:ResultSet → Statement → Connection(后创建先关闭,否则上层对象会依赖失效的底层连接)
事务管理
- JDBC 默认每条 SQL 自动提交
- 手动事务模式:
conn.setAutoCommit(false);// 关自动提交// ... 执行多条 SQL ...conn.commit();// 全部成功 → 提交// 出错时:conn.rollback();// 回滚 - 核心思想:多条 SQL 捆成一个原子操作,要么全成功要么全撤销
- 典型场景:转账(A 扣钱 + B 加钱,不能只执行一半)
连接池
- 连接很"贵":TCP 握手 + 认证 + 内存分配
- 连接池预先创建 N 个连接放着,用完归还,不销毁
- 类比:共享单车桩——骑完还回去,下一个人接着用
- 连接池 ≠ 缓存:连接池存的是"连接管道",缓存存的是"查询结果"
- 主流实现:Druid(阿里)、HikariCP、DBCP
三、重难点
难点1:关闭顺序为什么不能乱
- 结论:ResultSet → Statement → Connection
- 原因:ResultSet 依赖 Statement,Statement 依赖 Connection。先关 Connection,上层对象就废了
- 类比:拆楼要从上往下拆,不能先把地基炸了
难点2:PreparedStatement 防 SQL 注入的原理
- 结论:占位符机制让用户输入永远是"数据"而非"命令"
- 原因:预编译时 SQL 结构已固定,
?位置只能填入数据值,不会被解析为 SQL 关键字 - 类比:填表格——表格框架已经印好了,你只能在空格里写字,不可能改写表格结构
难点3:连接池为什么必要
- 结论:高并发下每个请求新建连接会迅速耗尽资源
- 原因:数据库连接是重资源,创建/销毁成本高
- 类比:每来一个顾客就现铺一条马路 vs. 提前修好高速公路,用完不拆
四、代码理解
最小完整示例(原生 JDBC)
// ① 注册驱动(MySQL 8.x)Class.forName("com.mysql.cj.jdbc.Driver");// ② 获取连接Stringurl="jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai";Connectionconn=DriverManager.getConnection(url,"root","password");// ③ 创建 PreparedStatementStringsql="SELECT * FROM user WHERE name = ?";PreparedStatementps=conn.prepareStatement(sql);ps.setString(1,"张三");// 填入占位符// ④ 执行 SQLResultSetrs=ps.executeQuery();// ⑤ 处理结果集while(rs.next()){System.out.println(rs.getString("name"));}// ⑥ 释放资源(后创建先关闭)rs.close();ps.close();conn.close();try-with-resources 最佳写法(推荐)
try(Connectionconn=DriverManager.getConnection(url,user,pwd);PreparedStatementps=conn.prepareStatement(sql);ResultSetrs=ps.executeQuery()){while(rs.next()){/* 处理 */}}// 自动逆序关闭:rs → ps → conn💡 实际开发中,以上代码你不会手写——MyBatis 或 JPA 已经帮你封装好了。这里学习原生写法是为了理解底层原理。
五、易错点
- MySQL 8.x 驱动类名写错:正确是
com.mysql.cj.jdbc.Driver,不是com.mysql.jdbc.Driver - 关闭顺序搞反:先关 Connection 会导致 ResultSet 和 Statement 报错
- 忘记关资源:不用 try-with-resources 时,必须在 finally 块逐一手动关闭
- URL 参数遗漏:MySQL 8.x 建议加上
useSSL=false&serverTimezone=Asia/Shanghai - 用 Statement 拼 SQL:哪怕只是内部工具,也养成用 PreparedStatement 的习惯
六、记忆口诀 / 通俗比喻
- JDBC 是什么:“外卖平台”——你只跟平台下单,平台帮你对接不同餐馆
- JDBC 的定位:“驾照科目一”——实际开车(MyBatis)有各种辅助,但科目一是原理基础,必须学
- 六步编程:“打电话”——拨号 → 接通 → 说话 → 对方回话 → 听 → 挂断
- PreparedStatement:“填表格”——表格框架固定,只填空格,没法改表格结构
- SQL 注入:“夹带纸条”——攻击者把纸条塞进信封,希望收信人当成正式文件执行
- 事务:“婚礼宣誓”——"我愿意"必须同时说,不能说一半改主意
- 连接池:“共享单车”——用完还桩上,下一个人接着骑
- 连接 vs 缓存:“高速公路 vs 备忘录”——路是通道,备忘录是记录
七、应用
JDBC 在实际开发中的角色
┌─────────────────────────┐ │ MyBatis / JPA / ... │ ← 你真正写代码的这一层 ├─────────────────────────┤ │ JDBC │ ← 底层标准接口(本章学的) ├─────────────────────────┤ │ JDBC 驱动(jar) │ ← 各数据库厂商提供 ├─────────────────────────┤ │ 数据库 │ ← MySQL / Oracle / ... └─────────────────────────┘- 原生 JDBC:学习阶段理解原理用,生产环境基本不手写
- MyBatis:国内最主流,半自动——SQL 你自己写,MyBatis 帮你处理参数映射、结果封装、连接管理等脏活累活
- JPA / Hibernate:全自动 ORM——连 SQL 都帮你生成,适合简单 CRUD
- 连接池:无论用哪个框架,底层都依赖连接池(Spring Boot 默认 HikariCP)
- 记住驱动类名和 URL 格式:这是每个 Java 项目的
application.yml里都会出现的"固定配置"
八、最终总结
JDBC 是 Java 操作数据库的底层基石。核心就三件事:获取连接 → 发 SQL → 处理结果。记住六步编程框架,永远用 PreparedStatement,上线必配连接池,多表操作开事务。
但实际开发中你不会手写这些——MyBatis、JPA 等框架已经帮你封装好了,它们底层调用的正是 JDBC。学好 JDBC 的意义不在于手写代码,而在于:当框架出问题时你知道底层发生了什么,看得懂报错,调得了性能。
