事务概述
在关系性数据库当中,事务是重要一环,它保证了数据的准确性,事务就是一组原子性的sql查询,一个独立的工作单元,事务内的语句,要么全部执行成功,要么全部执行失败。
事务的标准特征 ACID
| 特征 | 描述 |
|---|---|
| 原子性(atomicity,或称不可分割性) | 一个事务中的所有操作要么全部完成,要么全部不完成,如果执行过程中出现,数据回滚到事务开始前状态 |
| 一致性(consistency) | 在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等 |
| 隔离性(isolation,又称独立性) | 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致 |
| 持久性(durability) | 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失 |
关于一致性,我的理解是:假使创建了一张表user,user表有唯一索引等等相应的约束,那么你写入的数据必须遵循这些条件。
事务并发对于隔离性的挑战
| 情况 | 描述 |
|---|---|
| 脏读 | a事务能够查询到b事务变更的且未commit的数据 |
| 不可重复读 | 针对未commit的事务做了优化,即a事务只能读到已经提交修改数据的b事务,但问题是如果a的事务时间够长,a事务依据条件查询数据->data1, b事务update数据后commit,a事务依据相同条件查询数据->data2,即不可获得重复读取的数据 |
| 幻读 | a事务依据条件查询数据->data1, b事务insert数据后commit,a事务依据相同条件查询数据->data2,两次结果不一致,产生幻觉似的 |
不可重复读与幻读的区别
两者很类似,其实不可重复读的重点在于update与delete,而幻读在于insert。
四种隔离级别应对并发问题
| 隔离级别 | 描述 |
|---|---|
| 未提交读(Read uncommitted) | 允许脏读,即可以读取其他会话中事务未commit的数据 |
| 已提交读(Read committed) | 只能读取已经提交的数据,Oracle等多数数据库默认都是该级别 (不重复读) |
| 可重复读(Repeatable read) | mysql innodb引擎的默认级别,在同一事务何时查询,只要其他事务没有insert,其结果都是一致的,但还是存在幻读 |
| 可串行化(Serializable ) | 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞 |
mysql隔离级别实现原理
这一点可以当作扩展知识,对于数据库的使用者来说,一般不需要考虑这么多,知道某个隔离级别解决了什么样的问题即可。
未提交读
这玩意压根就没隔离,没有任务并发控制,性能较好
可串行化
读的时候加共享锁,也就是其他事务可以并发读,但是不能写。写的时候加排它锁,其他事务不能并发写也不能并发读。
可重复读与已提交读
在mysql当中,为了解决可重复读原理存在的幻读现象,加入了mvcc机制,
可重复读是在事务开始的时候生成一个当前事务全局性的快照,而读提交则是每次执行语句的时候都重新生成一次快照。对于一个快照来说,它能够读到哪些版本数据,要遵循以下规则:
- 当前事务内的更新,可以读到;
- 版本未提交,不能读到;
- 版本已提交,但是却在快照创建后提交的,不能读到;
- 版本已提交,且是在快照创建前提交的,可以读到;
利用上面的规则,两者主要的区别就是在快照的创建上,可重复读仅在事务开始是创建一次,而读提交每次执行语句的时候都要重新创建一次。