深入Spring事务之一:数据库事务基础知识
基础
谈Spring的事务之前,我们有必要对数据库事务的知识有个全面了解。
一荣俱荣,一损俱损很能体现事务的思想。
数据库事务有严格的定义,必须满足四个特性:
- 原子性(Atomic) :表示组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有操作执行成功,整个事务才提交。
- 一致性(Consistency): 事务操作成功后,数据库所处的状态和它的业务规则是一直的,即数据不会被破坏。
- 隔离性(Isolation): 在并发数据操作时,不同的事务拥有各自的数据空间,他们的操作不会对对方产生干扰。
- 持久性(Durability): 一旦事务提交成功后,事务中所有的数据操作都必须被持久化到数据库中。
在这些特性中,数据“一致性”是最终目标,其他特性都是未达到这个目标的措施、要求和手段。
数据并发
数据并发的问题,数据库中的相同数据可能被多个事务访问,就会导致各种并发问题。下面来看一下数据并发引发的问题。
脏读(dirty read):A事务读取B事务尚未提交的更改数据,并在这个数据的基础上操作。
| 时间 | 转账事务A | 转账事务B |
|---|---|---|
| T1 | 开始事务 | |
| T2 | 开始事务 | |
| T3 | 查询余额为1000元 | |
| T4 | 取出500,余额为500 | |
| T5 | 查询500元(脏读) | |
| T6 | 撤销事务,余额恢复1000元 | |
| T7 | 汇入100,余额为600元 | |
| T8 | 提交事务 |
不可重复读(unrepeatable read):A事务读取了B事务已经提交的更改数据。
| 时间 | 转账事务A | 转账事务B |
|---|---|---|
| T1 | 开始事务 | |
| T2 | 开始事务 | |
| T3 | 查询余额为1000元 | |
| T4 | 查询余额为1000元 | |
| T5 | 取出100,余额为900 | |
| T6 | 撤销事务,余额恢复1000元 | |
| T7 | 提交事务 | |
| T8 | 查询余额为900元(与T4不一样) |
幻象读(phantom read):A事务读取B事务提交的新增数据,这时A事务将出现幻象读问题。
| 时间 | 转账事务A | 转账事务B |
|---|---|---|
| T1 | 开始事务 | |
| T2 | 开始事务 | |
| T3 | 总款项为10000元 | |
| T4 | 新增一存款客户,存入10000元 | |
| T5 | 提交事务 | |
| T6 | 再次计算为10100元 |
幻象读和不可重复读容易混淆,前者是指读到了其他已经提交事务的新增数据,而后者是指读到了已经提交事务的更改数据。为了避免这两种情况,采取的对策是不同的:防止读取到更改数据,只需要对操作的数据添加行级锁,阻止操作中的数据发生变化;而防止读取到新增数据,往往需要添加表级锁—将整个表锁住,防止新增数据(Oracle使用多版本数据的方式实现)。
第一类丢失更新:A事务撤销时,把已经提交的B事务的更新数据覆盖了。
| 时间 | 转账事务A | 转账事务B |
|---|---|---|
| T1 | 开始事务 | |
| T2 | 开始事务 | |
| T3 | 查询余额为1000元 | |
| T4 | 查询余额为1000元 | |
| T5 | 汇入100,余额为1100 | |
| T6 | 提交事务 | |
| T7 | 取出100,改为900 | |
| T8 | 撤销事务 | |
| T9 | 余额恢复为1000(丢失更新) |
第二类丢失更新:A事务覆盖B事务中已经提交的数据,造成B事务所做操作丢失。
| 时间 | 转账事务A | 转账事务B |
|---|---|---|
| T1 | 开始事务 | |
| T2 | 开始事务 | |
| T3 | 查询余额为1000元 | |
| T4 | 查询余额为1000元 | |
| T5 | 取出100,余额为900 | |
| T6 | 提交事务 | |
| T7 | 汇入100 | |
| T8 | 提交事务 | |
| T9 | 余额该为1100(丢失更新) |
锁机制:
数据库通过锁机制解决并发问题。按照锁定对象的不同,一般可以分为行锁定和表锁定。 不同数据库在实现锁机制的时候细节不同,但是基本原理都是一样的。下面看Oracle数据库常用的五种锁定:
1.行共享锁定:一般通过select for update语句隐式获得行共享锁定。行共享锁定并不放置对数据进行更改的操作,但是可以放置其他会话获取独占性数据表锁定
2.行独占锁定:通过一条insert、update或delete语句隐式获取。这个锁定可以放置其他会话获取一个共享锁定、共享行独占锁定或独占锁定。
3.表共享锁定:可以防止其他会话获取行独占锁定,或者防止其他表共享行独占锁定或表独占锁定
4.表独占锁定:可以防止其他会话获取一个表共享、行独占或者表独占锁定,它允许其他行共享锁定
5.表独占:这个锁定防止其他会话对该表的任何其他锁定
事务隔离级别
数据库中,直接使用锁管理是非常麻烦的,因此数据库提供了自动锁机制,只要用户指定会话的事务隔离级别,数据库就会分析事务中的SQL语句,然后自动为事务操作的数据库添加上适合的锁。此外数据库还会维护这些锁。
ANSI/ISO SQL 92标准定义了4个等级的事务隔离级别,在相同环境下,使用不同隔离级别,可以导致不同的结果。
| 隔离级别 | 脏读 | 不可重复读 | 幻象读 | 第一类丢失更新 | 第二类丢失更新 |
|---|---|---|---|---|---|
| READ UNCOMMITED | 允许 | 允许 | 允许 | 不允许 | 允许 |
| READ COMMITTED | 不允许 | 允许 | 允许 | 不允许 | 允许 |
| REPEATABLE READ | 不允许 | 不允许 | 允许 | 不允许 | 不允许 |
| SERIALIZABLE | 不允许 | 不允许 | 不允许 | 不允许 | 不允许 |
SQL 92推荐使用REPEATABLE READ以保证数据的读一致性,不过这是可以选择的.
Mysql中,查看系统事务隔离级别:SELECT @@global.tx_isolation

浙公网安备 33010602011771号