JDBC 的事务和隔离级别
这里简单写一下我对 JDBC
的事务和隔离级别的理解。
名词解释
事务
数据库事务是 DBMS 执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
一个事务一定是具有原子性(atomic)
、一致性(consistency)
、隔离性(isolation)
、持久性(durability)
,即 ACID
。
一个事务会包含一个或多个数据操作语句(data-manipulation statements)
和查询语句。
通常来说,事务会依照如下的流程执行:
开始一个事务
执行一系列操作或查询语句
如果没有发生错误,则提交这个事务,并将其结束
如果发生了错误,则回滚这个事务,并将其结束。
ACID
- Atomic
原子性,即一个事务内的所有操作都被作为一个整体看待,要么全部成功,要么全部失败
- Consistency
一致性,即事务中有操作失败时,这个事务所更改的数据都必须回滚至操作前的状态。
- Isolation
隔离性,即事务所查看到的数据,要么是一个事务提交前的状态,要么是一个事务提交后的状态,而不可能是事务在执行中的状态。
- Durability
持久性,即事务对系统的影响是永久的。
读现象
- 脏读
当一个事务允许读取另一个事务修改但尚未提交的数据时,就有可能发生脏读。
- 不可重复读
在一次事务中,对一行数据的两次读取获得了不同的结果。
该现象发生于在执行 SELECT
时没有获得读锁,或者在读取完毕后立刻释放了读锁。
- 幻读
在事务执行过程中,两个完全一样的查询得到了不同的结果集,即是幻读。它是不可重复读的一个特殊场景。
当事务 1 在执行两次 SELECT ... WHERE
操作中间,事务 2 在这个表中生成了一行新数据,而这条新数据正好满足事务 1 的 WHERE
条件,导致事务 1 的两次查询得到了不同的结果集。
隔离级别
NONE
NONE
是一个特殊的级别,代表 JDBC
驱动不支持事务。
未提交读 (READ UNCOMMITED
)
这个是最低的隔离级别。
这个隔离级别允许事务读取到其他事务尚未提交 (commit) 的数据,即允许脏读。
提交读 (READ COMMITED
)
这个隔离级别中,DBMS 需要选定对象的写锁一直保持到事务结束,但是读锁会在 SELECT
操作完成后马上释放,所以有可能会发生 “不可重复读”。
可重复读 (REPEATABLE READ
)
在这个隔离级别下,DBMS 需要对选定对象的读锁和写锁一直保持到事务结束,但是不要求范围锁,所以有可能发生幻读。
可串行化 (SERIALIZABLE
)
这是最高的隔离级别。
在这个隔离级别下,要求 DBMS 在选定对象上的读锁和写锁一直保持到事务结束,如果使用了 WHERE
来描述范围时,则应当获取一个范围锁。这个隔离级别可以防止幻读。
隔离级别与读现象
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读 | 可能发生 | 可能发生 | 可能发生 |
提交读 | 不会发生 | 可能发生 | 可能发生 |
可重复读 | 不会发生 | 不会发生 | 可能发生 |
可串行化 | 不会发生 | 不会发生 | 不会发生 |
隔离级别与锁持续时间
隔离级别 | 写操作 | 读操作 | 范围操作 |
---|---|---|---|
未提交读 | 当前语句执行完毕 | 当前语句执行完毕 | 当前语句执行完毕 |
提交读 | 当前事务提交 | 当前语句执行完毕 | 当前语句执行完毕 |
可重复读 | 当前事务提交 | 当前事务提交 | 当前语句执行完毕 |
可串行化 | 当前事务提交 | 当前事务提交 | 当前事务提交 |