四大件各掏一张牌:DriverManager 发连接、Statement 干活分两路(增删改 executeUpdate / 查询 executeQuery)、ResultSet 靠 next() 逐行爬 + getXxx("列名") 取值——把这张方法地图背熟,JDBC 代码就能看懂一大半。
DriverManager:调度员只干一件事
Connection conn = DriverManager.getConnection(url, user, password);
- 注册驱动那步(
Class.forName(...))在 JDBC 4.0 之后驱动会自动注册,很多教材示例里看不到它了——但原理要懂(9.1 反射) - url 三段式,认结构就行:
jdbc:mysql://localhost:3306/javaweb?useSSL=false&serverTimezone=Asia/Shanghai
└─┬─┘ └─┬─┘ └───────┬────────┘ └─┬─┘└┬─┘└──┬──┘ └────── 参数(可选)──────┘
协议 子协议 主机 IP 端口 库名
- localhost = 本机,3306 = MySQL 默认端口;参数里
serverTimezone解决时区报错、useSSL=false关安全警告——新手连不上数据库一半的锅在这串参数上
Statement:干活分两路
Statement st = conn.createStatement();——从连接里造出来,之后按 SQL 的类型选方法:
| 方法 | 干什么 | 返回值 |
|---|---|---|
executeUpdate(sql) |
增删改(INSERT / UPDATE / DELETE) | int:受影响的行数 |
executeQuery(sql) |
查询(SELECT) | ResultSet:查到的结果集 |
记法:Update 是"改动世界",Query 是"看一眼世界"。改动有"改了几行"可数,查询只能给你一箱结果。
int rows = st.executeUpdate("INSERT INTO student VALUES(1,'波仔',18)");
System.out.println(rows > 0 ? "插入成功" : "没插进去"); // 返回值常用来判断成败
ResultSet rs = st.executeQuery("SELECT * FROM student");
拿 executeUpdate 执行 SELECT → 直接抛 SQLException;拿 executeQuery 执行 INSERT → 同样炸。一路一词,别串门。
ResultSet:光标从表头前出发
查回来的结果箱,光标初始停在表头前面(还没进数据区),必须 next() 才能读到第一行:
rs.next():光标往下挪一行——挪到数据返回true,挪过最后一行返回falsers.getString("name")/rs.getInt("age"):取当前行某一列的值(按列名取,最稳;列号也行但从 1 开始,不是 0!)- 完整遍历骨架(十级肌肉记忆):
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println(id + " " + name + " " + age);
}
10.2 读文件靠 read() != -1 收工,这里靠 next() == false 收工——都是"走到头就停",只是哨兵从 int 换成了 boolean。循环套路换汤不换药。
Demo12:五步套路完整骨架(API 总装)
还没装 MySQL 也能先把骨架敲熟——类和表名当剧本读:
public class Demo12 {
public static void main(String[] args) throws Exception {
// ① 注册驱动(新驱动自动,写上保险)
Class.forName("com.mysql.cj.jdbc.Driver");
// ② 获取连接
try (Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/javaweb?serverTimezone=Asia/Shanghai",
"root", "123456");
// ③ 造传话筒
Statement st = conn.createStatement();
// ④ 执行 SQL,拿结果集
ResultSet rs = st.executeQuery("SELECT * FROM student")) {
// ⑤ 逐行取值
while (rs.next()) {
System.out.println(rs.getInt("id") + " "
+ rs.getString("name") + " " + rs.getInt("age"));
}
}
}
}
- 三个资源(Connection、Statement、ResultSet)全是 AutoCloseable,try 括号里排排站,自动按倒序关闭
- 声明全用接口类型(
Connection/Statement),干活全靠驱动实现类——11.1 合同理论的现场直播
写一段查询代码,故意不调 next() 直接 rs.getString("name") → SQLException: Before start of result set——异常名就是"光标还没进门"的意思。
rs.getInt(1) 取的是第一列,rs.getInt(0) → 抛列号越界异常。带过无数新手的坑,一次记住。
st.executeUpdate("SELECT * FROM student") → SQLException。方法名就是分工,别串门。
常见误区
- 「忘了 next() 直接取值」——光标还在表头前,第一行根本没读,抛
Before start of result set。看到这个异常名就想起光标没进门。 - 「列号从 0 开始」——JDBC 的列号从 1 开始(和数组 0 开头正好相反)。但推荐按列名取,改表结构也不怕。
- 「executeUpdate 只能改数据」——它管所有"改动世界"的 SQL:INSERT、UPDATE、DELETE,甚至 CREATE TABLE,返回受影响行数。
- 「只有 Connection 要关」——Statement 和 ResultSet 也占资源,三件都要还。try-with-resources 排进括号自动倒序关。
- 「url 写错是运行前能发现的」——url / 账号 / 密码全错在运行时才炸(
CommunicationsException连不上、Access denied密码错),编译器帮不上,只能自己看异常信息对症。
自测一下
executeUpdate 干增删改,返回受影响行数 int;executeQuery 干查询,返回 ResultSet 结果集。Update=改动世界,Query=看一眼世界。
返回 boolean:成功挪到一行数据返回 true,越过最后一行返回 false。光标初始停在表头前面,所以第一行也必须先 next()。
推荐列名(改表不怕错位);列号从 1 开始不是 0。
jdbc:子协议://主机:端口/库名?参数。localhost=本机,3306=MySQL 默认端口。
参照 Demo12:Class.forName → try 括号排 Connection/Statement/ResultSet → getConnection(url,user,pass) → createStatement + executeQuery("SELECT * FROM student") → while(rs.next()) 里 getInt/getString 取值打印。自检点:三资源全进 try 括号、循环先 next 再取值。
下一步学什么
- ☑ 11.2 JDBC的常用API ✅ —— 点此复习:第十一章 JDBC/11.2 JDBC的常用API
- ☑ 11.3 JDBC编程 ✅ —— 点此复习:第十一章 JDBC/11.3 JDBC编程
相关笔记
- 第十一章 JDBC/11.1 什么是JDBC:四大件的角色与五步套路,本节是它的方法级展开
- 第十章 I-O/10.2 字节流:-1 哨兵 → next() 假值哨兵,循环收工同款思路
- 第五章 异常/5.2 运行时异常与编译时异常:SQLException 受检的原因
- 第九章 反射机制和注解/9.1 反射概述:Class.forName 注册驱动的本质
- 第四章 面向对象(下)/4.4 多态:接口声明、实现干活