事务和ACID

mysql只有在InnoDB引擎下是支持事务的,MyISAM是不支持事务的。

事务具有ACID(原子性,一致性,隔离性,持久性)

原子性 + 隔离性 + 持久性 是为了满足一致性

只有保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障。也就是说 A、I、D 是手段,C 是目的!

  • 无并发时,只需要保证原子性就能满足一致性
  • 有并发时,还需要保证隔离性才能满足一致性
  • 持久性是为了应对数据库宕机的情况

事务的隔离级别

MySQL有四种事务隔离级别:读未提交,读提交,可重复读,序列化。(可重复读是默认的隔离级别)

对应事务会发生的问题有三种:脏读,不可重复读,幻读(都发生在多线程下)

三种问题含义如下

  1. 脏读:事务A读到的num数据,是事务B修改后还没提交的数据
  2. 丢失修改(Lost to modify):ab事务都访问了同一数据,在a事务中修改了这个数据后,b事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。
  3. 不可重复读:事务A读到的num数据后,事务B修改了num数据并提交,A此时再读num会发生和第一次读不一致的情况
  4. 幻读:和不可重复读类似,只不过此时B事务是insert了新的行,A事务读到了和第一次不一样数量的结果。
  • 读未提交:都不能解决
  • 读提交:可以解决脏读
  • 可重复读:可以解决不可重复读
  • 序列化:解决幻读

读未提交和串行化基本上是不需要考虑的隔离级别,前者不加锁限制,后者相当于单线程执行,效率太差。

并发事务的控制方法

MySQL 中并发事务的控制方式有两种:MVCC(多版本并发控制,Multiversion concurrency control)

  • 锁的分类
    • 行级锁,表级锁(innoDB支持行级锁,粒度小,并发性能好。MyISAM只支持表级锁)
    • 行级锁是针对索引字段的,如果没有命中唯一索引,或者索引失效,那么会导致对所有记录加锁
    • 共享锁,排他锁(一般是读锁和写锁)
  • MVCC是对同一个数据有存储多个版本,通过事务的可见性保证事务只能看见自己对应的版本。
    • MVCC是依赖隐藏字段,Read View,undo log实现的
    • undo log用于记录某行数据的多个版本
    • read view和隐藏字段用来判断当前版本对数据是否可见

MyISAM 和 InnoDB 有什么区别?

  1. 是否支持行级锁
    • MyISAM只支持表级锁,InnoDB支持行级锁
  2. 是否支持事务
    • MyISAM不支持,InnoDB支持
  3. 是否外键
    • MyISAM不支持,InnoDB支持
  4. 索引的实现不同
    • 虽然 MyISAM 引擎和 InnoDB 引擎都是使用 B+Tree 作为索引结构,但是两者的实现方式不太一样。
    • InnoDB 引擎中,其数据文件本身就是索引文件。
    • MyISAM,索引文件和数据文件是分离的。
  5. 是否支持数据库异常崩溃后的安全恢复
    • InnoDB通过redo log支持
    • MyISAM不支持

mysql的索引数据结构

mysql为了加快数据的查找,引入了索引。

对于一张表的某个字段建立索引之后,当以此列作为查询条件时,可以加速查询。

mysql索引底层数据结构有B+树,Hash索引,Full-text索引,和R-tree索引。(不止有b+tree索引) 不过默认使用的是B+树索引,可以在创建表的时候指定索引类型。

  1. 哈希索引

    哈希索引适合用于等值查询非常频繁的场景,比如一些简单的查询场景。哈希索引不能支持范围查询、模糊查询等其他类型的查询操作,而且哈希索引无法避免哈希冲突,会降低查询效率。在处理大量数据时,哈希索引的性能会受到影响。

  2. Full-text索引

    全文索引,只支持innodb和myisam引擎

  3. R-树索引

    R-树索引只支持MyISAM和InnoDB引擎,不支持其他引擎。

  4. B+树索引

    B+树是b树的一种升级,b+树的非叶子节点不包括数据本身,所以每次查询都需要查询到叶子节点,b+树的叶子节点是一条链表,可以加快范围查询的速率。

    因为b+树的非叶子节点中没有数据本身,所以一个节点可以包含多个子节点,导致b+树比传统的b树要更为矮胖一些,减少数据库查询的io次数

mysql的索引分类

按照存储方式分

  1. 聚簇索引(聚集索引):索引和数据存放在一起,InnoDB中的主键索引就属于聚簇索引
    • 优点:查询快
    • 缺点:更新代价大,依赖有序添加
  2. 非聚簇索引: 索引和数据分开存放,二级索引就是非聚簇索引。MyISAM引擎的索引都是非聚簇索引
    • 非聚簇索引查询到对于的主键id后,需要回表到主键索引中查询对应的数据。当此非聚簇索引是覆盖索引时,不需要回表。
    • 优点:更新代价小
    • 缺点:可能会二次查询(回表)

按照索引状态分

  1. 主键索引:列值唯一且不能为NULL,每张表只能有一个主键索引
    如果一张表没有声明主键索引,mysql会生成一个隐藏列作为主键索引
  2. 普通索引:加快查询
  3. 唯一索引:列值为一(可以为null),每张表可以有多个唯一索引
  4. 覆盖索引:一个索引包含(或者说覆盖)所有需要查询的字段的值。
  5. 联合索引:多个列值组合成一个索引,用于组合搜索
  6. 全文所有:对内容进行分词搜索。

mysql的三大日志

mysql包含redo log,undo log和bin log

  1. bin log:他记录了每一个对数据库表和数据库数据的增删改操作,用于主从复制和主从备份等用途

  2. redo log:

    在讲redo log之前,先讲述一下mysql读取的背景

    mysql的数据是以数据页为单位存储的,对于每次查询,mysql会将整个数据页查询出来。为了加快每次的查询,对于之前已经查询的数据页,会放在缓存中,如果缓存没命中,才会去查询数据库。

    那么就出现了一个问题:如果有修改此页数据的操作,那么是修改缓存还是数据库本身?

    redo log就应运而生了,对于修改操作,我们只修改在缓存中的数据页,并不修改数据库本身。但是会在redo log结尾添加此操作,到时将redo log中的修改刷盘到数据库中。

    因为每次我们修改的数据可能只有几B大小,那么每次去修改16kb的数据页是不现实的。修改数据库是随机读取和写入,在redo log后追加是顺序写入,更快。

  3. undo log:主要用于实现事务的回滚,实现MVCC

    对于每次事务,undo log记录于修改操作相反的操作,如果需要回归事务,那么就按照undo log将数据库恢复。

    实现MVCC时,根据每个事务的可见性不同,达到多版本控制。