银行转账举例:
转账是生活中常见的操作,比如从A账户转账100元到B账号。站在用户角度而言,这是一个逻辑上的单一操作,然而在数据库系统中,至少会分成两个步骤来完成:
- 将A账户的金额减少100元
- 将B账户的金额增加100元。
在这个过程中可能会出现以下问题:
- 转账操作的第一步执行成功,A账户上的钱减少了100元,但是第二步执行失败或者未执行便发生系统崩溃,导致B账户并没有相应增加100元。
- 转账操作刚完成就发生系统崩溃,系统重启恢复时丢失了崩溃前的转账记录。
- 同时又另一个用户转账给B账户,由于同时对B账户进行操作,导致B账户金额出现异常。
数据库事务
- 数据库事务是构成单一逻辑工作单元的操作集合。
- 是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行。
事务的四大特性(ACID):
- 原子性
事务中的所有操作作为一个整体像原子一样不可分割,要一起执行,不能只执行其中一部分。 - 一致性
事务的执行结果必须使数据库从一个一致性状态到另一个一致性状态。
事务的操作,其中有一步失败。所有步骤全部撤回,需重新操作。 - 隔离性
多个事务并发执行时,A事务的处理不能处理B事务。 - 持续性
一个事务一旦提交,它对数据库的修改将永久保存。
隔离级别
-
Read Uncommitted(读未提交)
(1)一个事务可以读取另一个另一个未提交事务的数据。
(2)会出现脏读:事务A 读取 事务B 更新后但未提交的数据,如果 事务B 回滚,则 事务A 督导脏数据。 -
Read Committed(读提交)
(1)事务A 要等到 事务B 提交后才能读取数据。
(2)可解决不可重复读问题:事务A 多次读取 事务B,在 事务B 没有提交前,如果 事务B 恰好修改这个数据。再次读时,事务A 两次读取的数据不一样。 -
Repeatable Read(重复读)
(1)在开始读取数据,即事务开始时,不允许修改操作。
(2)可解决幻读问题:在 A事务 中查询某条记录,发现没有此信息。过一会试图更新该条记录,意外的成功了。再次读取这条记录时,读取成功。实则是利用时间差,第一次查询时此数据还未添加。 -
Serializable(序列化)
所有事务按顺序执行,但由于串行执行,效率大大降低。
四种隔离级别可能导致的问题:
-
Serializable(串行化)
最严格的级别,事务串行执行,资源消耗最大。 -
REPEATABLE READ(重复读)
保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。
避免了 “脏读取” 和 “不可重复读取” 的情况,但不能避免 “幻读” ,但是带来了更多的性能损失。 -
READ COMMITTED (读提交)
大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”,但不能避免“幻读”和“不可重复读取”。
该级别适用于大多数系统。 -
Read Uncommitted(读未提交)
事务中的修改,即使没有提交,其他事务也可以看得到,会导致“脏读”、“幻读”和“不可重复读取”。