当前位置: 代码迷 >> 综合 >> MySQL学习日志(三)—— 事务、锁、MVCC
  详细解决方案

MySQL学习日志(三)—— 事务、锁、MVCC

热度:67   发布时间:2023-12-05 10:43:23.0

事务、锁、MVCC

一、事务

事务就是一个完整的业务逻辑单元,可以保证多个操作(DML))的原子性,要么全部成功,要么全部失败。

1、事务的过程:

  1. 开启事务机制

  2. 执行DML语句,将操作记录记录到数据库的操作历当中,但是不会修改实际数据持久化到磁盘

  3. 结束事务。

    提交会把修改后的数据持久化到磁盘;

    回滚事务,根据历史日志将数据恢复,两种操作都会把历史操作日志清空

2、事务的特性(ACID)

  1. 原子性:事务就是最小的工作单元,不可再分

  2. 一致性:事务必须保证DML同时成功或失败回滚

  3. 隔离性:事务A和事务B的读写具有隔离性

  4. 持久性:最终数据必须持久化到磁盘,事务才算结束

二、锁

1、读锁:共享锁、S锁

加读锁的情况:

select * from table lock in share mode
此时其他线程只能读取数据,修改数据会进入阻塞状态,只能等待锁释放或者线程超时

2、写锁:排它锁、X锁:

加写锁的情况:

  1. select * from table for update

    • 在读已提交的隔离级别下:

      1.事务A执行select * from table where b=1 for update,事务B执行select * from table where b=2 for update

      发现事务B没有被阻塞可以执行,所以在读已提交的隔离级别下,for update写锁只是把查询出来的行记录加上了锁,没有查询出的结果依然可以加锁

      2.insert操作可以插入数据

      事务A执行select * from table where b=1 for update,事务B执行insert table (a,b) values (1,1),可以插入,这样就造成了幻读

    • 在可重复读的隔离级别下:

      1.事务A执行select * from table where a=1 for update,事务B执行select * from table where a=2 for update

      发现事务B没有阻塞可以执行,所以for update写锁只是把查询出来的行记录加上了锁,没有查询出的结果依然可以加锁

      2.insert操作不能插入数据

      事务A执行select * from table where b=1 for update,事务B执行insert table (a,b) values
      (1,1),这个时候触发了间隙锁,为了不造成幻读,必须保证符合where条件的数据不能被插入

  2. DELETE:首先锁定这一行,再去删除

  3. UPDATE:首先锁住这一行,再去更新

  4. INSERT:插入一条记录,会先加入“隐式锁”来保护插入的记录在本事务提交前不被别的事务访问到

3、行锁
  1. LOCK_REC_NOT_GAP:单个行记录上的锁
  2. LOCK_ORDINARY间隙锁:根据主键排序,对于行本身以及上下行的间隙添加锁,主要是解决幻读的问题

三、MVCC

多版本并发控制。

多个线程并发访问或者操作数据库的时候,有的在读有的在写,数据不一致的问题怎么办?

  1. 加行级锁、间隙锁。会导致效率降低
  2. 用MVCC

当前读、快照读:

  • 当前读:每次读取的数据都是最新版本。以下几种情况会保证每次读取的是最新的数据
  1. insert/update/delete
  2. select * from table for update
  3. select * from table lock in share mode
  • 快照读:读取的是历史记录(存在undo日志文件中的记录)
三大组件

一、隐藏字段:

  • trx_id:每一个行记录都会包含一个用户不可见的字段:trx_id–>存的是最后一次创建或修改该记录的事务id
  • row_id:隐藏主键
  • roll_pointer:存储的是回滚指针。每次对聚簇索引修改的时候,就会把老版本写入undo日志,如果事务执行失败,需要回滚到修改之前的状态,通过roll_pointer指针,指向上一版本中的位置,通过它来获得上一个版本的记录信息

二、undolog(回滚日志)

保存的是数据的历史版本状态,一条数据可以存在多条undolog日志信息。

三、readview的生成时机

事务在进行快照读的时候产生的视图

read committed:每次进行快照读的时候都会生成readview

repeatable read:只有在第一次进行快照读的时候才会生成readview,之后的读操作都会用第一次生成的readview

  相关解决方案