工作也有好几年了,一直在用数据库,但是一些基本知识老容易遗忘,现在整理一下,作为复习。
数据库事物有严格的定义,满足4个特性:
①原子性(Atomicity):事务中的所有元素作为一个整体提交或回滚,事务的个元素是不可分的,事务是一个完整操作。
②一致性(Consistemcy):事物完成时,数据必须是一致的,也就是说,和事物开始之前,数据存储中的数据处于一致状态。保证数据的无损。例如,A账户给B账户转账,无论操作是否成功,A和B的存款总额是不变。
③隔离性(Isolation):对数据进行修改的多个事务是彼此隔离的。这表明事务拥有各自的数据空间,它们的操作不会对对方产生干扰。
④持久性(Durability):事务完成之后,事物中的所有数据库操作都必须持久化到数据库。
事务的标准定义: 指作为单个逻辑工作单元执行的一系列操作,而这些逻辑工作单元需要具有原子性, 一致性,隔离性和持久性四个属性,统称为ACID特性。
数据库的并发问题
数据库中的数据可能同时被多个事务访问,如果没有采取必要的隔离措施,会导致并发问题。问题归纳为5类:脏读、不可重复读、幻读以及两类更新问题(第一类丢失和第二类丢失)。
脏读(dirty read)
A事务读取到B事务尚未提交的更改数据,并在这个数据基础上修改。
时间 | 事务A | 事务B |
T1 | 事务开始 | |
T2 | 事务开始 | |
T3 | 查询余额为1000 | |
T4 | 取出500元,余额改为500元 | |
T5 | 查询账户余额为500元(脏读) | |
T6 | 事物撤销,余额恢复为1000元 | |
T7 | 汇入100元,余额改为600元 | |
T8 | 事物提交 |
在这个业务中,B事务取款500后又撤销了,A在往账户中转账100元时,读取了B事务尚未提交的改动,造成账户损失500元。
不可重复读(unrepeatable read)
A事务在操作过程中,读取了B事务提交的修改数据,造成在同一个事务中同一份数据不一致。
时间 | 事务A | 事务B |
T1 | 事务开始 | |
T2 | 事务开始 | |
T3 | 查询余额为1000 | |
T4 | 查询账户余额为1000 | |
T5 | 提现100元,余额改为900元 | |
T6 | 事务提交 | |
T7 | 查询账户余额为900元(不可重复读) |
在A事务中,T4和T7时间点数据不一致。
幻读(phantom read)
常发生在统计数据的时候:A事务读取B事务提交的新增数据。
时间 | 事务A | 事务B |
T1 | 事务开始 | |
T2 | 事务开始 | |
T3 | 统计总存款额10000元 | |
T4 | 新增一个账户,存入100元 | |
T5 | 事务提交 | |
T6 | 再次统计总存款10100元 |
新增数据正好满足查询条件,在A事务中两次统计的结果不一样。
幻读和不可重复读的概念很相似,区别在于前者是读到了其他事务提交的新增数据,后者是读到了已经提交的数据修改。区别这两个概念主要是由于避免这两种情况的策略不同,防止读到更改的数据需要对数据添加行级锁,而防止读取到新增数据,需要添加表级锁——将整个表锁住。
第一类丢失更新
A事务撤销的时候,把已经提交的B事务的更新数据覆盖了。(不知道Oracle是怎么解决的~~)
时间 | 事务A | 事务B |
T1 | 事务开始 | |
T2 | 事务开始 | |
T3 | 查询余额为1000元 | |
T4 | 查询余额为1000元 | |
T5 | 转入100,余额改为1100元 | |
T6 | 事务提交 | |
T7 | 取出100元,余额改为900元 | |
T8 | 事务撤销 | |
T9 | 余额恢复为1000(丢失更新) |
实际上,是A事务“撤销”了B事务的操作。
第二类丢失更新
A事务覆盖了B事务已经提交的数据,比较常见~~
时间 | 事务A | 事务B |
T1 | 事务开始 | |
T2 | 事务开始 | |
T3 | 查询余额为1000元 | |
T4 | 查询余额为1000元 | |
T5 | 提现100,余额改为900元 | |
T6 | 事务提交 | |
T7 | 转入100元 | |
T8 | 事务提交 | |
T9 | 余额改为1100元(丢失更新) |
事务A“覆盖”了事务B的操作。
事务的隔离级别
如果程序直接通过锁实现事务管理,会非常麻烦,好在现在的数据库都提供一定的数据库隔离级别。
隔离级别 | 脏读 | 不可重复读 | 幻读 | 第一类丢失 | 第二类丢失更新 |
READ UNCOMMITED | 有 | 有 | 有 | 无 | 有 |
READ COMMITED | 无 | 有 | 有 | 无 | 有 |
REPEATABLE READ | 无 | 无 | 有 | 无 | 无 |
SERIALIZABLE | 无 | 无 | 无 | 无 | 无 |
事务的隔离级别和数据库并发性是对立的,此消彼长。到最高的SERIALIZABLE级别,基本是串行了。
另外,具体的事务隔离有赖于数据库的支持,不一定每个数据库都支持上述的隔离级别,也有可能几个隔离级别是等效的情况,具体情况请参考数据库文档。
参考资料:
http://blog.csdn.net/zdwzzu2006/article/details/5947062