美文网首页
Mysql锁、事务隔离级别详解

Mysql锁、事务隔离级别详解

作者: MrZhang2019 | 来源:发表于2019-08-26 19:54 被阅读0次

    一、MySQL锁

    锁是计算机协调多个进程或线程并发访问某一资源的机制。 在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一 个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。
    很多人在开发过程中,应该注意到很多锁的问题,在数据库中,有时候我们没有给SQL语句加锁,这些SQL语句也正常的运行,那是因为MySQL自动帮我们加了隐式锁,在某些其他特殊情况,可能会需要我们自己主动加锁。

    1、锁分类

    在MySQL中,锁机制比较简单,并且不同的存储引擎支持不同的锁机制。

    • MyISAM 存储引擎采用表锁。
    • BDB 存储引擎采用页面锁,也支持表锁。
    • InnoDB 存储引擎即支持表锁,也支持行锁,默认使用行锁。

    从性能上分为:悲观锁乐观锁
    从数据操作类型上分为:读锁写锁。(都属于悲观锁)
    读锁(共享锁):针对同一份数据,多个读操作可以同时进行并且不会相互影响
    写锁(排他锁):在写操作完成之前,会阻塞其他写锁和读锁。
    从数据操作粒度上分为:表锁行锁

    1.1 表锁

    每次操作锁住整张表,开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

    • 手动增加表锁:lock table 表名称 read(write),表名称2 read(write);
    • 查看表锁:show open tables;
    • 删除表锁:unlock tables;

    1)手动增加表读锁


    表锁语句

    当前session和其他session都可以读该表


    查询结果

    当前session中插入或者更新锁定的表都会报错,其他session插入或更新则会等待


    更新结果

    2)手动增加表写锁


    查询结果
    更新结果

    3)查看表锁情况


    查看表锁情况

    4)删除表锁


    删除表锁

    结论:MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行增删改操作前,会自动给涉及的表加写锁。表锁中读锁会阻塞写,但是不会阻塞读;写锁则会阻塞读和写。

    1.2 行锁

    每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。
    上面说了,MyISAM 只支持表锁,InnoDB可以支持表锁和行锁,但是,InnoDB只有通过索引条件检索数据才使用行级锁,否则,InnoDB也会走表锁。所以说:InnoDB的行锁是基于表索引的。同时,InnoDB 与 MyISAM 引擎的不同之处还有,InnoDB支持事务

    1、行锁支持事务

    在并发事务中,可能会带来如下问题:

    • 脏读:事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。(针对未提交数据)
    • 不可重复读:事务A读取到了事务B已经提交的修改数据。(针对其他提交前后,读取数据本身的对比)
    • 幻读:事务A读取到了事务B提交的新增数据。(针对其他提交前后,读取数据条数的对比)
    • 更新丢失:当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。

    1) 事务的隔离级别
    脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数 据库提供一定的事务隔离机制来解决。
    事务的隔离级别就是通过锁的机制来实现,锁的应用最终导致不同事务的隔离级别,只不过隐藏了加锁细节,事务的隔离级别有4种:

    事务隔离级别
    数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔 离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。
    mysql默认事务隔离级别为:可重复读(REPEATABLE-READ)
    查看mysql事务隔离级别:
    5.7版本:
    show variables like 'tx_isolation';
    8.0版本:
    show variables like 'transaction_isolation';
    

    2、行锁分析

    通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况

    show status like '%Innodb_row_lock%'
    
    image.png

    对各个状态量的说明如下:
    Innodb_row_lock_current_waits: 当前正在等待锁定的数量
    Innodb_row_lock_time: 从系统启动到现在锁定总时间长度
    Innodb_row_lock_time_avg: 每次等待所花平均时间
    Innodb_row_lock_time_max: 从系统启动到现在等待最长的一次所花时间
    Innodb_row_lock_waits: 系统启动后到现在总共等待的次数

    优化建议:

    • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
    • 合理设计索引,尽量缩小锁的范围尽可能减少检索条件范围,避免间隙锁
    • 尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql尽量放在事务最后执行
    • 尽可能低级别事务隔离

    相关文章

      网友评论

          本文标题:Mysql锁、事务隔离级别详解

          本文链接:https://www.haomeiwen.com/subject/kfzdectx.html