# 事务


## ***事务***

1. ***事务是什么***
   
   - *事务就是要么全部完成 要么全部失败 目的是为了保证数据的一致性*

2. **事务的ACID**
   
   - *`原子性`保证全部完成 要么全部失败 没有中间状态 他是靠 `undo日志`来实现的*
   - *`持久性`事务修改后的数据会一直存在 他是靠 `redo日志`来实现的*
   - *`隔离性`多个事务之间不会互相影响，他是靠`MVCC`也就是`undo log`来实现的*
   - *`一致性`多个事务修改数据后 数据都是一致的*

3. **事务的隔离级别（InnoDB引擎中, 定义了四种隔离级别供我们使用 级别越高性能越低 而隔离性是由mysql的各种锁和MVCC机制来实现的）**
   
   - *`读未提交`我们可以去读事务未提交的数据，会带来 脏读，不可重复读，幻读的问题*
   - *`读已提交`我们只可以去读事务已经提交的数据，会带来不可重复读，幻读的问题*
   - *`可重复读`一个事务不管读取多少次，读的都是以第一次读的快照为标准，会带来幻读的问题*
   - *`串行化`直接串行，一个事务一个事务来，这样效率就会及其低下*

4. **事务当中存在的可能问题**
   
   - *`脏读`事务A正在修改数据，事务B去读了，随后A发生了问题callback，B读取的数据就会无效*
   - *`不可重复读`事务A正在更新数据，事务B去读数据了，随后事务A更新完毕，事务B再去读取，发现前后数据不一致*
   - *`幻读`事务A正在插入数据，事务B读取全部数据，在事务A插入前后读取数据不一致 发现数据多了一行*

5. **事务4大隔离级别实现原理**
   
   - ***串行化*** 
     
     `排他锁`和`共享锁`来实现的
     
     - **读锁（共享锁，S锁）**
       - `select ... lock in share mode;`
       - *读锁是共享的，多个事务可以同时读取同一个资源，但不允许其他事务修改*
     - **写锁（排他锁，X锁）**
       - `select ... for update;`
       - *写锁是排他的，会阻塞其他的写锁和读锁，update、delete、insert都会加锁*
   
   - ***可重复读 & 读已提交***
     
     - *他们俩是靠MVCC机制来实现的*

## ***Copy On Write***

1. ***什么是COW***
   - *`写入时复制` 当有写入操作时 将原表copy一份 专门供来修改 如果此时有查询操作 则就查询原表，等新表写入完成在替换原表*
   - *经常用于 **读多写少** 高并发的场景下，但是不单单只用于该场景*

## ***MVCC***

1. ***什么是MVCC***
   - *多版本控制链*
   - *他跟COW还是很像的，都是在并发下保证数据安全 并且提高效率*
2. **MVCC如何实现的**
   - *在我们的undo-log记录的数据表中 其实是有两个字段 一个是记录着事务的**唯一ID**，一个是**回滚指针**指向上一个事务*
   - *比如我们现在update一个数据 那么这个更新后的数据的回滚指针就会指向之前的数据，后面也是一样的道理 所以就形成了一个多版本控制链*

## ***小谈阿里面试题 - 查询操作方法需要使用事务吗***

 *这种题其实大部分都要视情况而定, 如果你在查询的时候只有一条sql语句 那肯定是没必要开启事务的 但是如果你在导出的场景下 而且隔离级别是可重复读的情况下 导出的数据肯定是需要同一个时间维度的数据 所以这时候需要开启事务，否则就会导致导出的数据中 数据其实不是同一个时间维度的数据*

## ***MySQL执行过程与BufferPool缓存机制***

1. ***mysql为何要如此设计***
   - *因为mysql要为其性能考虑，kafka为何吞吐量这么高，因为他的写入数据是顺序写，顺序写的性能是相当高*
   - *mysql写入 `redo-log`的时候就是顺序写，但是通过IO线程写入ibd确实随机写，虽然可以优化，但是性能肯定是比不过顺序写*
2. **redo-log 为何可以顺序写，ibd确实随机写**
   - *`redo-log`他是记录日志 记录日志本来就可以直接添加在文件末尾的，不会插入或者写在开头*
   - *ibd却不一样 我们有多个ibd 因为表有多个，随后我们写数据可能会插入，开头也插入一个数据，所以这里就必须随机写*

