MySQL 1 锁&MVCC

█ 1.数据库三范式

级别 概念
1NF 属性不可分 列 原子性
2NF 非主键属性,完全依赖于主键属性 满足第一范式
3NF 非主键属性无传递依赖

█ 2.数据库锁

乐观锁 || 悲观锁 || b共享锁 S锁 || b排它锁 X锁 || b行锁 || b表锁

2.1 乐观锁:

 一般的实现乐观锁的方式就是记录数据版本。尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。

 自己实现的锁,认为数据一般不会冲突,实现方式:版本号+时间戳





2.2 悲观锁:

一般认为数据被并发修改的概率比较大,所以需要在修改之前先加锁。处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;降低并行性。
for updata加锁





2.3 b共享锁 S锁 || b排它锁 X锁 || b行锁 || b表锁

b共享锁 S锁 :只读数据操作, 非独占 加 HOLDLOCK

b排它锁 X锁 :一个事务,只能写,加了这个锁,其他事务不能再加任何锁for update

b行锁 : 作用于数据行

b表锁 : 作于用表

█ 3.关系型数据库和非关系型数据库区别

关系型数据库 MySQL SQLserver Oracle

优点

1、容易理解:二维表结构;

2、使用方便:通用的SQL语言使得操作关系型数据库非常方便;

3、易于维护:丰富的完整性,减低了数据冗余和数据不一致的概率;

4、支持SQL,可用于复杂的查询。

5、支持事务


缺点
1、读写性能比较差,维护一致性困难;

2、固定的表结构,灵便度不好;

3、高并发读写时,硬盘I/O存在瓶颈;不支持海量数据的高效率读写;

4、可扩展性不足



非关系型数据库 MongoDB HBase Elasticsearch

1、使用键值对存储数据;
2、分布式;

优点
1)格式灵活:数据存储格式非常多样,应用领域广泛,而关系型数据库则只适用基础的关系模型。

2)性能优越:NOSQL是根据键值对的,不用历经SQL层的分析,因此 性能非常高。

3)可扩展性:基于键值对,数据之间耦合度极低,因此容易水平扩展。

4)低成本:非关系型数据库部署简易,且大部分可以开源使用。


缺点
1)不支持sql,学习和运用成本比较高;

2)无事务处理机制;

3)数据结构导致复杂查询不容易实现。


3.1 关系型与非关系型数据库的区别:

3)储存格式:Nosql的储存文件格式是key,value方式、文本文档方式、照片方式这些,能储存的对象种类灵活;关系数据库则只适用基础类型。

4)可扩展性:关系型数据库有join那样的多表查询机制限定造成拓展性较差。Nosql依据键值对,数据中间沒有耦合度,因此容易水平拓展。

5)数据一致性:非关系型数据库注重最终一致性;关系型数据库注重数据整个生命周期的强一致性。

6)事务处理:SQL数据库支持事务原子性粒度控制,且方便进行事务回滚;NoSQL也支持事务处理,但可靠性不足,其价值在于可扩展性和大数据量处理。

█ 4. MySQL两大引擎MyIsam和InnoDB

○ 4.1 聚簇索引 和 非聚簇索引

○ 4.2 MyIsam 和 InnoDB 区别


○ 4.3 MyIsam 查询流程 InnoDB

4.3.1 MyIsam 查询流程



4.3.2 InnoDB 查询流程


!!!innodb支持全文索引是从mysql5.6开始的

█ 5. 数据库四种隔离级别:

1.读未提交 2.读已提交RC 3.可重复度RR默认,且开启间隙锁 4.串行化<效率差>

串行化:是数据库最高的隔离级别,这种级别下,事务“串行化顺序执行”,也就是一个一个排队执行。
这种级别下,“脏读”、“不可重复读”、“幻读”都可以被避免,但是执行效率奇差,性能开销也最大,所以基本没人会用。
大多数数据库默认的事务隔离级别是Read committed,比如Sql Server , Oracle。

Mysql的默认隔离级别是Repeatable read。

█ 6. 数据库事务四大特性 ACID

ACID
事务的特点:要么都成功,要么都失败

1)原子性Atomicity,要么执行,要么不执行

2)一致性Consistency,事务前后,数据总额一致

3)隔离性Isolation,所有操作全部执行完以前其它会话不能看到过程

4)持久性Durability,一旦事务提交,对数据的改变就是永久的



6.1 a原子性

6.1 undo log

   要不全成功,要不全部,

   undo log 实现原子性,回滚,如果报错 回滚到执行之前的状态,,
   undo log会记录执行的信息,回滚做相反的操作,记录到日志里面 



6.2 c一致性:

   数据库的完整性。完整性体现在:数据库的主键要唯一 || 字段类型大小长度符合要求 || 外键要符合要求

  外键:删除的时候 子表先删除,能删除父表
      CREATE TABLE `example1` (
          `stu_id` int(11) NOT NULL DEFAULT '0',
          `course_id` int(11) NOT NULL DEFAULT '0',
          `grade` float DEFAULT NULL,
          PRIMARY KEY (`stu_id`,`course_id`)
      );
      CREATE TABLE `example2` (
          `id` int(11) NOT NULL,
          `stu_id` int(11) DEFAULT NULL,
          `course_id` int(11) DEFAULT NULL,
          PRIMARY KEY (`id`),
          KEY `f_ck` (`stu_id`,`course_id`),
          CONSTRAINT `f_ck` FOREIGN KEY (`stu_id`, `course_id`) REFERENCES `example1` (`stu_id`, `course_id`)
      );
      insert into example1 (stu_id,course_id,grade)values(1,1,98.5),(2,2,89);
      insert into example2 (id,stu_id,course_id)values(1,1,1),(2,2,2);

      delete from example2 where stu_id=2; 子
      delete from example1 where stu_id=2; 父


6.3 d持久性 :

6.3 redo log

  buffer:
      MySQL 的数据是存在磁盘中的,磁盘IO效率很低,,innodb提供了一个缓存buffer,buffer包含了磁盘中部分数据页的映射,作为访问数据库的缓冲,
      读,先buffer,无磁盘,再写入buffer
      写,先buffer,定期刷新到磁盘上   --- 数据丢失

  redo log 防止数据丢失,,预写式日志,修改先写入日志,再buffer


redo log 速度比 buffer 快的原因:

1)
  buffer中的数据持久化 是随机写的IO,每次修改的数据的位置 是 随机的。
  redo log 是追加模式,在文件尾部追加,顺序IO  快  kafka也是顺序IO

2)
  buffer持久化数据 是以 数据页page为单位的,MySQL默认是16k一个page,只要这个page有修改,就要整个写入
  redo log 只要写入真正修改的部分,无效IO大大减少。

3)
  redo log 先放到 redo log 缓冲区,,之后写入到磁盘。



○ 6.4 i隔离性:

i隔离性:分为两种情况:

   1)写-写操作:锁

   2)写-读操作:MVCC   可以解决(脏读/不可重复读/幻读)读写冲突 无锁并发控制

数据库并发场景


█ 7 i写写操作:innodb有 行锁 // 表锁 // 间隙锁

查看锁情况的sql语句:innodb_locks


X是排他锁   对应的有共享锁

b共享锁 S锁 :只读数据操作,  非独占 加 HOLDLOCK  

b排它锁 X锁 :一个事务,只能写,加了这个锁,其他事务不能再加任何锁for update   

○ 7.1 record 行锁

    drop table if exists test_innodb_lock;
    CREATE TABLE test_innodb_lock (
        a INT (11),
        b VARCHAR (20)
    ) ENGINE INNODB DEFAULT charset = utf8;
    insert into test_innodb_lock values (1,'a');
    insert into test_innodb_lock values (2,'b');
    insert into test_innodb_lock values (3,'c');
    insert into test_innodb_lock values (4,'d');
    insert into test_innodb_lock values (5,'e');

    创建索引
    create index idx_lock_a on test_innodb_lock(a);
    create index idx_lock_b on test_innodb_lock(b);

    先将自动提交事务改成手动提交:set autocommit=0;

    启动两个会话窗口 A 和 B,抢锁

行锁(写&读)"读已提交"

COMMIT;之后就可以了



行锁(写&写)

窗口 A 执行 COMMIT;操作,B自动出结果了。



行锁分析命令代码


○ 7.2 表锁 写写操作 i

MyIsam最小锁粒度是 表锁
用了 OR 做连接,索引就会失效。

窗口 A 执行 COMMIT;操作,B自动出结果了。表锁的等待时长长。

○ 7.3 间隙锁


█ 8 当前读 & 快照读

当前读

快照读

○ 7.4.2 RC、RR级别下的InnoDB快照读区别

█ 9 i读写操作:MVCC

MVCC 是“维持一个数据的多个版本,使读写操作没有冲突”的一个抽象概念。

○ 9.1 MVCC解决并发哪些问题

○ 9.2 MVCC的实现原理




undo log a原子性

redo log d持久性



ReadView




Read View可见性判断条件 代码

○ 9.3 MVCC解决 RC读已提交/脏读 RR可重复度/不可重复读

数据库四种隔离级别:
1.读未提交  2.读已提交RC  3.可重复度RR默认,且开启间隙锁 4.串行化
2.读已提交RC  3.可重复度RR 都是基于 MVCC实现的
RC
活跃事务ID是没有提交的,,提交的事务ID是可以被访问到的,

1)脏读:指一个事务中访问到了另外一个事务未提交的数据,MVCC解决 RC读已提交


2)不可重复读:一个事务查询同一条记录2次,得到的结果不一致。 在一个事务里面,只会生成一个 ReadView,都用的第一个生成的。

RR MySQL默认
在一个事务里面,只会生成一个 ReadView,都用的第一个生成的。

通过版本链和ReadView 就实现了 读已提交,但是没有实现可重复读

在一个事务里面,两个select方法 会生成两个ReadView,
第二个select可能会查到最新提交的 数据
一个事务里 两个select查询到了不同的数据,就不是可重复读RR 违背了数据库四种隔离级别。

3)幻读:一个事务查询2次,得到的记录条数不一致。

(1)什么是幻读

1、在可重复读隔离级别下,普通查询是快照读,是不会看到别的事务插入的数据的,幻读只在**当前读**下才会出现。

2、幻读专指**新插入的行**,读到原本存在行的更新结果不算。因为**当前读**的作用就是能读到所有已经提交记录的最新值。
幻读 
保证数据的一致性和事务与事务之间的隔离性。

RR存在幻读的问题,在Innodb搜索引擎里被解决了,
读分为 当前读(锁) + 快照读(MVCC)


 快照读(MVCC)一个事务一个ReadView,select结果都相同;
 当前读(锁) + 间隙锁(锁住一段事务)  ,MySQL默认且开启间隙锁
(2)幻读产生的原因

行锁只能锁住行,即使把所有的行记录都上锁,也阻止不了新插入的记录。 
posted @ 2021-05-24 21:25  千面鬼手大人  阅读(83)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css