1.事务的ACID属性
事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作。事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。
原子性(atomic),事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行
一致性(consistent),事务在完成时,必须使所有的数据都保持一致状态。
隔离性(insulation),由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。
持久性(Duration),事务完成之后,它对于系统的影响是永久性的。
2.mysql更新丢失
a.第一类丢失更新(lost update): 在完全未隔离事务的情况下,两个事物更新同一条数据资源,某一事物异常终止,回滚造成第一个完成的更新也同时丢失。
b.第二类丢失更新(second lost updates):是不可重复读的特殊情况,如果两个事务都读取同一行,然后两个都进行写操作,并提交,第一个事务所做的改变就会丢失。
c.脏读(dirty read):如果第二个事务查询到第一个事务还未提交的更新数据,形成脏读。
d.幻读(phantom read):一个事务执行两次查询,第二次结果集包含第一次中没有或者某些行已被删除,造成两次结果不一致,只是另一个事务在这两次查询中间插入或者删除了数据造成的。
e.不可重复读(unrepeated read):一个事务两次读取同一行数据,结果得到不同状态结果,如中间正好另一个事务更新了该数据,两次结果相异,不可信任。
3.事务的四种隔离等级,按照安全性由高到低分别为
a. Serializable 串行化
b. Repeatable Read 可重复读
c. Read Commited 可读已提交
d. Read Uncommited 可读未提交
隔离级别 | 脏读 | 不可重复读 | 幻读 | 第一类丢失更新 | 第二类丢失更新 |
---|---|---|---|---|---|
READ UNCOMMITED | 允许 | 允许 | 允许 | 不允许 | 允许 |
READ COMMITTED | 不允许 | 允许 | 允许 | 不允许 | 允许 |
REPEATABLE READ | 不允许 | 不允许 | 允许 | 不允许 | 不允许 |
SERIALIZABLE | 不允许 | 不允许 | 不允许 | 不允许 | 不允许 |
4.悲观锁和乐观锁
a.悲观锁:大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。
b.乐观锁:为了避免悲观锁的性能问题,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现。
乐观锁的工作原理:读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
5.innodb事务特性
a.innodb能检测到死锁,可能返回错误,也可能将持有最少行级排他锁的事务进行回滚
b.innodb存储引擎在修改表数据时,使用事务日志,用追加的方式保存修改记录,将随机IO方式改为了顺序IO方式,提高处理速度、
c.事务默认采用自动提交,如果不是显示开始一个事务,则每个查询都被当做一个事务执行提交操作
6.InnoDB的事务隔离等级以及如何解决幻读:
innodb引擎默认使用REPEATABLE READ(可重复读)隔离级别。该隔离级别还是会产生幻读问题。还
需要使用next-key locking技术启动事务来避免幻读。
具体实现是:事务A针对非唯一索引查询时,会使用排它锁 锁住索引前后两个范围,其他事务无法在此范围内写入数据,这样事务A多次查询的记录数都是一样的
间隙锁问题参考 mysql 间隙锁
7.InnoDB存储引擎MVCC的实现策略:
MVCC将数据库的行锁与行的多个版本结合起来,只需要很小的开销,就可以实现非锁定读,从而大大提高数据库系统的并发性能.
MVCC实现原理:MVCC保存某个时间点上的数据快照。一个事务内,看到的是同一个版本的快照,数据一致。不同事务在同一时间点看到的数据会不一致,因为他们得到的数据版本不一样。InnoDB在每行记录存在额外的隐藏字段,其中一列存储行被更新的版本号,另外一列存储行被删除的版本号。每当一个事务开始的时候,innodb都会给这个事务分配一个递增的版本号,所以版本号也可以被认为是事务号.对于每一个”查询”语句,innodb都会把这个查询语句的版本号同这个查询语句遇到的行的版本号进行对比,然后结合不同的事务隔离等级,来决定是否返回该行。当隔离级别是REPEATABLE READ时,这种策略下,select、delete、 insert、 update语句如何操作:
1) SELECT:如果要查询的行被行锁锁定,为了提高效率会去读取undo日志,提高了效率。如果没有锁定呢?根据条件查询出结果并过滤掉deleteVersion早于当前事务的行?
2) INSERT: 对新插入的行,行的更新版本被修改为该事务的事务号
3) DELETE:对于删除,innodb直接把该行的被删除版本号设置为当前的事务号,相当于标记为删除,而不是实际删除。innodb有一定规则来触发真正的删除操作
4) UPDATE:在更新行的时候,innodb会把原来的行复制一份到undo段中,并把当前的事务号作为该行的创建版本?(undo日志到底存的什么?)
在每一行数据中额外保存两个隐藏字段:当前行创建时的版本号和删除时的版本号(可能为空)。每个事务又有自己的版本号,这样事务内执行CRUD操作时,就通过版本号的比较来达到数据版本控制的目的。具体做法见下面的示意图。
MVCC缺点:为了实现多版本,InnoDB需要维护额外的隐藏字段,以及清理不需要的行版本,带来额外开销。