存储引擎

Innodb和MyIsAM区别

(1)事务:Innodb支持事务。
(2)行锁:Innodb支持行锁。
(3)数据存储:Innodb索引和数据存储在同一个文件(dba文件),MyIsAM索引和数据分开存储。
(4)外键:Innodb支持外键约束。

事务

事务的四大特性(ACID)

原子性:一个事务的执行,要么全部成功,要么全部失败。
一致性:一组SQl执行之前,数据必须是准确的,执行之后,数据也是准确的。多个事务读同一条数据都是相同的。
隔离性:并发访问数据库,一个事务不被其他事务所干扰。
持久性:事务提交之后,对数据库的改变是持久性的,不会因为数据库发生故障而丢失改变。

并发事务带来的问题

  • 脏写(丢失修改):一个事务修改了数据,但是还没提交事务,此时另外一个事务过来也修改了数据,导致前一个事务修改的数据丢失。(另外一种解释:有一条数据,name=’张三’的age字段为null,事务A针对这条数据修改了age=18,但是还未进行提交,然后事务B同样也过来修改这条数据,修改了age=20,然后事务A在修改过程中发现一些问题,导致事务回滚,将缓存值又重新置为null,就导致事务B修改的age值丢失了)
  • 脏读(读未提交):某个事务修改了值,但是并未提交,此时另外一个事务就能读到未提交事务的值,然后就读到了读未提交的值。(事务A对name=’张三’的数据的age字段置为18,但事务并未提交,此时事务B读取到的值就是18,然后事务A发生了一些问题,导致事务回滚,age字段值又变成了null,此时事务B再去读取数据,发现读到的name=’张三’的age值为null。)
  • 不可重复读:在避免了脏读的问题以后,事务A在执行时,先查询了一个数据值是1,然后过段时间,事务B把那个数据给修改并提交了,此时事务A再次查询这个数据就成了值2。所以,事务A两次读取相同行的数据值不一样,就是不可重复读。
  • 幻读:上面三种情况针对的其实都是某条数据的修改。幻读的情况针对的是插入。比如事务A读取了指定name=’张三’的数据有2条,但是事务B此时又插入一条新的name=’张三’的数据,然后事务A在重新读取name=’张三’的数据就有3条数据结果返回。

对于脏写和脏读的问题,原因都是因为修改后的数据还未及时写入磁盘内导致的。
无论是脏写还是脏读,都是因为一个事务去更新或者查询了另外一个还没提交的事务更新过的数据。
**

事务的隔离级别

读未提交(RU级别):允许读取事务尚未提交数据。可能会出现脏读,不可重复读,幻读问题
读提交(RC级别):只能读取事务已提交的数据。可能会出现不可重复读,幻读问题
可重复读(RR级别):对同一条数据的多次读取结果都是一样的,除非是事务本身修改了数据。 可能会出现幻读。
可串行化:最高隔离级别,完全服从ACID原则。多个事务之间依次执行(这么做其实也不算是并发了)。这种做法可以防止脏读,不可重复读和幻读。

MVCC多版本并发控制

MySQL设置隔离级别为RR(可重复读)级别,可以同时防止脏读,不可重复读和幻读。
Innodb存储引擎,会在每行数据最后加两个隐藏列,一个保存行的创建时间对应的事务ID,一个保存行的删除时间对应的事务ID。(注:事务ID在mysql里面是自己维护的,是自增且全局唯一)。

image.png

  • 一个事务在查找一条数据的时候,只能读取到比自己创建事务ID小的事务。

比如, 事务ID=121的事务,在查询id=1的这一行数据的时候,只能找到小于等于事务ID=121的那一行数据(即id=1的数据)。

  • 一个事务在查找一条数据的时候,如果当前事务小于删除事务ID,则能够读取到删除前的数据

比如,事务ID=121的事务,是小于删除事务ID=122的,所以事务ID=121还是能够读取到id=1的数据。

  • 当事务ID=121的事务读取id=2的数据,读到的结果的name=李四。

因为 事务ID=121 大于 创建事务ID=119,小于 创建事务ID=122。

总结:
在一个事务内查询的时候,mysql只会查询创建时间的事务ID小于等于当前事务ID的行(其实就是mysql存储的一个事务快照),这样可以保证这个行是在当前事务中创建或者是之前创建的。同时,一个行的删除时间的事务ID要么没有定义(没有删除),要么是比当前事务ID大(事务开启之后才被删除),此时就还能够读取到相关数据。
事务对某行记录的查询,其实查的始终是之前的那个快照(快照创建时间小于当前事务ID,然后快照的删除时间大于当前事务ID),这样就能让这个事务在运行期间,会一直读取到这条数据的同一个版本快照。