MySQL高级——锁与事务

Posted oahaijgnahz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL高级——锁与事务相关的知识,希望对你有一定的参考价值。

mysql高级(二)——锁与事务



Java、大数据开发学习要点(持续更新中…)


一、MySQL锁机制**

1.1 锁与其应用场景

MySQL的锁按照数据操作类型分为:读锁(共享锁)、写锁(独享锁)【读读共享,读写、写写互斥】
按照数据操作的粒度分为:行锁 和 表锁

锁的类型和适合的场景

  • 表锁:适合读多场景,偏向MyISAM存储引擎,开销小,加锁快,锁粒度大,并发度低。
  • 行锁:适合事务场景,偏向InnoDB存储引擎,开销大,加锁慢,锁粒度小,并发度高。

读阻塞写、写阻塞读

  • 读阻塞写当一个会话在一个表中加了读锁,那么其他会话也能读此表数据,但是其他表的写数据请求会被阻塞。并且当前表在未释放此表的读锁之前,不能对其他表进行操作,不能对自己读锁定的表进行写数据操作。

  • 读阻塞写当一个会话在一个表中加了写锁,那么其他会话 读写 此表数据阻塞。本会话可以读写此表。

      										总结一下就是:读锁阻塞写,写锁阻塞读写
    

手动锁定一行实现一个事务

begin;

select * from test where id=8 for update;

--do your job

commit;

行锁升级为表锁的情况

无索引或者索引失效的情况下(如SQL中varchar字段的查询没带引号,但MySQL内部优化进行了自动类型转换,但导致索引失效了),行锁升级为表锁。隐秘又恐怖的情况

间隙锁的问题

MySQL在对数据进行范围条件操作而不是等值条件操作时,InnoDB会给符合条件的已有数据索引项加锁。而存在范围中的根本不存在的记录也会被加锁,其他会话对这个不存在的记录行进行新增操作会被阻塞,这种锁机制被称为——间隙锁。但间隙锁可以用来在repeatable read的隔离级别下防止幻读的发生,所以MySQL在repeatable read隔离级别下也是不会发生幻读的。(等值查询就根本不用说幻读了,范围查询靠间隙锁防止幻读)

1.2 事务与MySQL隔离级别

1.2.1 事务与事务的ACID属性***

MySQL的事务是由一组SQL语句组成的逻辑处理单元,具有事务的四个属性ACID:

  • 原子性(Atomic):事务是个原子操作,要么成功要么失败。
  • 一致性(Consistent):事务开始和完成时,数据保持一致状态。所有事务对一个数据的读取结果都是一致的。
  • 隔离性(Isolation):支持事务的系统提供一定的隔离性,保证事务在并发环境下能不受干扰地完成,对其他事务不可见。
  • 持久性(Durable):事务完成后,对数据有持久化机制,保证即使系统故障也能恢复数据。

1.2.2 并发场景事务存在的问题**

  • 更新丢失:多个事务对同一数据行进行修改时,彼此不知道对方的存在,造成一方的数据丢失。
  • 脏读:事务A读取了事务B修改了尚未提交的数据,此时事务B回滚,A读取的数据无效,不符合一致性。
  • 不可重复度:事务A多次读取某一行数据,但期间事务B对此行数据修改并提交了,两次读取数据不一致,不符合隔离性。
  • 幻读事务A读取到了事务B的新增数据,不符合隔离性。

1.2.3 MySQL事务隔离级别

隔离级别读数据一致性脏读不可重复读幻读
未提交读(read uncommitted)最低级别,只能保证不读取物理损坏数据
已提交读(read committed)语句级
可重复读(repeatable read)默认级别,事务级
串行化(serializable)最高级别,事务级

也就是MySQL默认配置下是存在幻读问题的,隔离级别和并发是负相关的,隔离级别越高越趋向于串行执行,这与并发能力是矛盾的。所以根据业务场景需求,来采用相应的隔离级别。

1.2.4 MVCC协议

MVCC工作在repeatable read和read committed两种隔离级别下

加锁的实现有加锁同步和CAS机制,MVCC就类似于CAS机制。InnoDB引擎下,上述两种隔离级别,MySQL对读写数据不加行锁,而是使用多版本控制的方式。这样读写操作不会阻塞,但需要额外的存储空间来实现,使用空间换时间的方法。(基于版本号控制,每个事务有递增的事务版本号,也是可以在可重复读隔离级别下避免幻读的)

MVCC在每行后面保存两个隐藏的列,用来存储两个版本号:创建版本号删除版本号。而每一个事务在启动的时候,都有一个唯一的递增的事务版本号。并且操作是通过原数据行快照的形式进行的

插入操作时 : 记录的创建版本号就是事务版本号。

更新操作时:先标记旧的那行记录为已删除,并且删除版本号是当前事务版本号,然后插入一行新的记录,其创建版本号也是当前事务版本号。

删除操作时:就把事务版本号作为删除版本号。

从上面的描述可以看到,在查询时要符合以下两个条件的记录才能被事务查询出来:

  1. InnoDB只查找版本早于当前事务版本的数据行,这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。

  2. 行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未被删除。

     				总结一下就是,查找行快照创建版本号小于当前事务版本号,且删除版本号大于当前事务版本号或者未定义。
    

MVCC的事务回滚是通过一个Undo日志将每个数据行的快照链接起来,通过Undo日志来回滚事务。

二、MySQL主从复制*

主从复制
MySQL主从复制分为三步(MySQL复制是异步的且串行化的):

  1. master将操作写入binary log中。其中的记录过程叫做二进制日志事件。
  2. slave将master的二进制日志事件拷贝到其中继日志中(relay log)。
  3. slave重做中继日志中的事件,将改变应用到自己的数据库中。

canal从MySQL抽取增量数据也是这个原理,它将自己伪装成一个slave。

以上是关于MySQL高级——锁与事务的主要内容,如果未能解决你的问题,请参考以下文章

MySQL高级——锁与事务

MySQL索引锁与事务

mysql死锁(锁与事务)

MySQL事务及实现隔离级别及锁与优化

mysql 锁与事务的一些概念

云原生技术分享 | MySQL锁与事务的并发性