第一部分:JDBC 驱动与 URL
1.1 JDBC 的定位
- JDBC 是 Java 连接数据库的接口规范,原生操作数据库就靠它;后来才有 Hibernate、MyBatis 等封装产品。
- JDBC 实现类由各数据库厂商提供,叫驱动类,如 MySQL、Oracle 各有自己的驱动,它是代码与库之间的桥梁,使用需导入对应依赖包。
重点:驱动版本最好与数据库版本匹配,库是 5 就导 5 的驱动,8 就导 8 的;高版本驱动可兼容低版本库(如 8 驱连 5 库),但不建议这么做。
易错点:不要把 JDBC 当实现类------它只是规范,真正干活的是厂商驱动。掌握 JDBC 接口方法后,换数据库只换驱动即可。
1.2 JDBC 快速入门与常用类
- 准备库、表和数据,再按固定流程写程序:加载驱动、获取连接、编写并执行 SQL、遍历结果集、关闭资源。
- 常用类中,
DriverManager负责加载驱动类。 - URL 是重点,由主协议、子协议、主机 IP、数据库名组成。
易错点:MySQL 8 版本 URL 必须加时区,5 版本不需要,否则 8 版会报错。是否加 UTF-8 编码,看数据库编码是否一致,一致用默认即可。
1.3 SQL 操作分类
- JDBC 执行 SQL 分查询和增删改(
update)两类;另有批处理、清理等少用操作了解即可。 - 结果集通过
get类型方法取字段并释放资源。 - SQL 注入此前已讲。
易错点:不要把这些普通 SQL 操作误认涉事务,只有事务相关才是重点。
1.4 JDBC 七步定位问题
- 若对 JDBC 操作数据库的七个步骤都不理解,应先确认班级此前是否讲过该内容。
- 找到之前和当天下午的录屏重看一遍,结合图解把步骤再过一遍。
重点:学习时必须定位到具体哪一步有问题,而非笼统说"都不懂"。难点是步骤间的顺序与依赖关系易混淆,需对照视频和图解逐点梳理。
第二部分:事务概念
2.1 事务概述
事务是数据库提供的一个特性:组成各个数据的执行单元,要么都成功,要么都不成功。
转账例子:冠希给美美转 1000 元。
先给冠希扣除 1000 元
再给美美加上 1000 元
事务结束
- 背后是两条 SQL,但属共同体。
- 事务前后总数据量不变:如两人各 1 万,转后总额仍 2 万。
易错点:不要把事务里多条 SQL 当独立操作,必须捆绑看成一个单元。
难点:理解"最小逻辑单元"不可分------可类比打包快递,拆开就失效。
2.2 事务控制的位置
- 事务控制是在数据库客户端层面进行的,如 cmd 窗口或 Navicat 这类图形化工具,都属于 MySQL 客户端操作,不属于高级语言操作数据库的范畴。
- 例:用
mysql -u root -p登录,切换到jdbc demo库,在数据库层面展示如何控制事务、看清事务全貌。
易错点:不要以为事务控制写在 Java 等代码里才算,客户端直接发指令也是正经的事务控制方式。
第三部分:MySQL 中操作事务
3.1 准备数据
建表语句:
create table t_account(
id int primary key auto_increment,
username varchar(20),
money double
);
插入测试数据:
insert into t_account values (null,'美美',10000);
insert into t_account values (null,'冠希',10000);
insert into t_account values (null,'小凤',10000);
insert into t_account values (null,'熊大',10000);
insert into t_account values (null,'熊二',10000);
3.2 默认事务机制
- MySQL 默认自动提交:不改任何设置时,一条 SQL 语句就是一个事务。
- 若无显式控制,每条 SQL 各算各的,独立提交。
易错点:不要以为连续操作自动同事务;未显式控制就每条 SQL 独立提交,想多句绑一起必须手动开事务。
3.3 事务的必要性
- 转账中,钱从一方划走、另一方未加上就崩溃,必须保证要么转账成功,要么回滚回原账户。
- 单条 SQL 虽能持久化,但回滚命令可能失效,导致错误结果被定死。
重点:需主动用回滚等机制保证一致性,不能依赖单条语句自动处理,否则崩溃会造成数据错乱。
3.4 在 MySQL 中操作事务的两种方式(重点)
方式一:使用命令显式开启事务
start transaction; -- 开启事务
update t_account set money = money - 1000 where username = '冠希';
update t_account set money = money + 1000 where username = '美美';
commit; -- 提交事务(事务已经结束,数据永久保存到数据库中)
-- 或
rollback; -- 回滚事务(事务已经结束,数据回滚到最初始化的状态)
重点:
- 事务结束只有提交或回滚两种方式,一旦结束,
start transaction指令失效。 - 没开事务的修改不受回滚保护,回滚只对当前未结束事务有效。
commit提交后事务结束,改动落盘,此时再rollback毫无意义。- 未提交前回滚可撤销。
方式二:设置 MySQL 事务不默认提交
MySQL 数据库的事务默认是自动提交的,默认使用一个事务。设置不默认提交:
set autocommit = off; -- 或 set autocommit = 0;
编写 SQL 语句(执行完都没有提交):
update t_account set money = money - 1000 where username = '冠希';
update t_account set money = money + 1000 where username = '美美';
需要手动提交或回滚:
commit;
-- 或
rollback;
查看事务是否默认提交:
show variables like 'autocommit';
设置不默认提交后,再执行上面的两条 update,最后手动 commit 或 rollback。
易错点:
- 不要以为执行完 SQL 就生效,必须
commit才真正提交。 - 不要以为没开事务也能回滚,自动提交下单行 SQL 已落库。
- 要区分"显式事务"(
start transaction)和"关闭自动提交后的隐式手动事务"(set autocommit = off)。
第四部分:JDBC 中操作事务
4.1 Connection 接口
操作事务需要掌握 Connection 接口提供的方法:
| 方法 | 作用 |
|---|---|
void setAutoCommit(boolean autoCommit) |
传入 false,设置数据库事务不默认提交 |
void commit() |
提交事务 |
void rollback() |
回滚事务 |
Connection 接口的两个作用:
操作数据库都需要使用 Connection 接口
管理事务
4.2 JDBC 控制事务的唯一方式
- JDBC 控制事务只有一种方式:把连接对象的默认自动提交关闭,即
setAutoCommit(false)。 - 没有
start transaction那种写法,因为Connection对象只提供这个方法。 - 之后若捕获异常就
rollback,全部执行成功再commit。
核心流程:
关自动提交 → 异常回滚 → 正常提交
易错点:
- 不要以为有类似 MySQL 客户端的开启事务写法,JDBC 只有这一种方式。
- 不要以为框架各有各的事务开关,MyBatis 及 MyBatis-Plus 也是基于
setAutoCommit(false)实现,并非另起一套;底层统一走 JDBC 这一种机制。
第五部分:事务四大特性 ACID
| 特性 | 说明 |
|---|---|
| 原子性 Atomicity | 事务中操作是不可再分割的原子单位,要么全部成功,要么全部失败 |
| 一致性 Consistency | 事务执行后,数据库状态与其他业务规则保持一致;如转账无论成功与否,两账号余额之和不变 |
| 隔离性 Isolation | 并发操作中,不同事务之间应隔离开来,使每个并发中的事务不会相互干扰 |
| 持久性 Durability | 一旦事务提交成功,数据操作必须持久化到数据库;即使提交后数据库马上崩溃,重启时也必须能恢复数据 |
重点:
- 原子性保整体成败。
- 一致性保业务总额规矩不被破坏。
- 持久性是事务结束后数据永久保留。
- 隔离性最关键也最难理解,因涉及并发场景。
例:张三给李四转账时,王五同时给赵六转账完全允许,这是两套事务,不能让彼此产生影响,就像两条并行车道互不影响。
易错点:隔离性指并发任务各自独立、不冲突,不论是否操作同一数据。
第六部分:不考虑隔离性引发的问题
| 问题 | 定义 | 关键词 |
|---|---|---|
| 脏读 | 一个事务读取到了另一个事务未提交的数据 | 未提交 |
| 不可重复读 | 一个事务读取到了另一个事务提交的数据,导致多次查询结果不一致 | update,修改记录 |
| 虚读(幻读) | 一个事务读取到了另一个事务提交的数据,导致多次查询结果不一致 | insert,向表中添加数据 |
6.1 脏读
银行柜台类比:A、B 柜台各开事务,A 柜台张冠希给美美转 1000 元但还没提交,此时 B 柜台查询却看到冠希少 1000、美美多 1000------这就是读了未提交的变更。
重点:未提交的事务结果不该被别的事务看见,否则数据不可靠。
6.2 不可重复读
两个事务同时开启,A 提交了但 B 还没结束,B 在自身未结束时读到了 A 提交的结果,破坏隔离性,叫不可重复读。
6.3 虚读/幻读
表现也是多次查询结果不一致,但针对的是另一事务的 insert 操作,比如 A 事务中 B 事务插入数据使记录数变多。
易错点:
- 脏读对应"未提交",不可重复读对应"已提交",但都发生在多事务并发、相互干扰的场景。
- 区分不可重复读与幻读,核心看另一事务动的是改还是增。
第七部分:事务隔离级别
7.1 四种隔离级别
| 隔离级别 | 解决的问题 |
|---|---|
Read uncommitted |
什么都解决不了 |
Read committed |
避免脏读,但不可重复读和虚读有可能产生 |
Repeatable read |
避免脏读和不可重复读,虚读有可能产生 |
Serializable |
避免各种读 |
7.2 安全性与效率
安全性:Serializable > Repeatable read > Read committed > Read uncommitted
效率: Serializable < Repeatable read < Read committed < Read uncommitted
重点:安全与效率互斥,越安全(约束多)效率越低,越不安全效率越高。按安全或效率取舍级别即可。
7.3 数据库默认隔离级别
| 数据库 | 默认隔离级别 |
|---|---|
| Oracle | Read committed(第二种) |
| MySQL | Repeatable read(第三种),避免脏读和不可重复读 |
重点:
- 第一种和第二种一般不考虑。
- MySQL 默认第三种,虽避免幻读,但不是靠隔离级别本身,而是 InnoDB 引擎通过锁和 MVCC 版本控制实现,属 MySQL 架构内容,可先搁置。
- 隔离级别排序:读未提交、读已提交、可重复读、串行化;
RR是 MySQL 默认可重复读,属第三档。
易错点:不要误以为"避免幻读"是隔离级别直接完成的。
7.4 隔离级别演示要点
查看当前隔离级别:
select @@tx_isolation;
设置隔离级别(提交结束后再设):
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
演示结论:
| 隔离级别 | 演示现象 |
|---|---|
| 第一种(读未提交) | 左侧能读到右侧未提交的中间值,出现脏读;若右侧 rollback,你看到钱转走又没了 |
| 第二种(读已提交) | 左侧查不到右侧未提交的变更,脏读被阻止;但右侧提交后,左侧同一事务内重查结果变化,出现不可重复读 |
| 第三种(可重复读) | 未提交时无脏读;提交后左侧再查仍是原值,多次查询一致,避免不可重复读 |
| 第四种(串行化) | 可避免幻读,但演示效果不好,建议搜 AI 写示例;一般不考虑该级 |