事务的定义
理论上说,事务有着极其严格的定义,他必须同时满足4个特性,即通常所说的事务的ACID特性。
- A(Atomicity) 原子性:操作必须是原子的
- C(consistency) 一致性:事务某个动作失败了,系统可以自动撤销事务,返回初始化状态,保存一致性
- I (isolation) 隔离性:并发控制 串行化 锁 等称呼
- D(durability)持久性 : 事务提交之后就是永久性,即使发生宕机事故也要能恢复数据
事务的实现
事务的原子性,一致性,持久性是通过数据库的redo log 和 undo log实现的
日志类型 | 作用 | 写入规则 | |
---|---|---|---|
redo | 保证原子性和持久性 | 物理日志,记录页的物理修改操作 | 顺序写 |
undo | 保证一致性 | 逻辑日志,根据每行记录进行记录,帮助事务回滚以及MVCC | 随机读写 |
redo log
mysql支持三种将redo log buffer写入redo log file的时机,可以通过innodb_flush_log_at_trx_commit参数配置,各参数值含义如下:
参数值 | 含义 |
---|---|
0(延迟写) | 事务提交时不会将redo log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到redo log file中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。 |
1(实时写,实时刷) | 事务每次提交都会将redo log buffer中的日志写入os buffer并调用fsync()刷到redo log file中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。 |
2(实时写,延迟刷) | 每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到redo log file。 |
undo log
重做日志记录了事务的行为,和redo log不同
undo log分为:
- insert undo log
- update undo log
insert undo log 是在insert操作中的产生undo log。因为insert操作的记录,只对事务本身可见,其他事务不可见。
隔离级别
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | 是 | 是 | 是 |
不可重复读 | 否 | 是 | 是 |
可重复读 | 否 | 否 | 是(innodb否) |
串行化 | 否 | 否 | 否 |
innodb可重复读中解决幻读是通过下面两种
主要通过以下两种情况避免幻读
普通读:快照读(非阻塞读)伪MVCC 表象避免幻读,是RR下查找数据,第一次读取创建快照,后面读取都是读取本次快照,不论别的事务是否提交相关更改,我们都不知道,掩耳盗铃
因为普通读是不会加锁的读,故不会有next-key locks的使用,解决幻读的手段是MVVC
当前读:next-key锁(行锁+gap锁) 上了锁,你别的操作不会修改我锁定的区间了,我就
所谓当前读,指的是加锁的select(S或者X), update, delete等语句。在RR的事务隔离级别下,数据库会使用next-key locks来锁住本条记录以及索引区间。
拿上面那个例子来说,在RR的情况下,假设使用的是当前读,加锁了的读
select * from table where id>3 锁住的就是id=3这条记录以及id>3这个区间范围,锁住索引记录之间的范围,避免范围间插入记录,以避免产生幻影行记录。
脏读
事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
不可重复读
事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
幻读
第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样.
MVCC
英文全称为Multi-Version Concurrency Control,翻译为中文即 多版本并发控制。他无非就是乐观锁的一种实现方式。如果把乐观锁看成一个接口,MVCC便是这个接口的一个实现而已。
锁
- 行锁
- 表锁
- 间隙锁
当我们用范围条件检索数据而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合范围条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在 的记录,叫做“间隙(GAP)”。
间隙锁的作用
- 为了防止幻读(上面也说了,Repeatable read隔离级别下再通过GAP锁即可避免了幻读)
- 满足恢复和复制的需要:MySQL的恢复机制要求在一个事务未提交前,其他并发事务不能插入满足其锁定条件的任何记录,也就是不允许出现幻读