Mysql

首页 -  Mysql  -  Mysql事务的4大隔离级别

Mysql事务的4大隔离级别

SQL 标准定义了四种隔离级别,MySQL 全都支持。这四种隔离级别分别是:

1.隔离级别

    1.读取未提交(READ UNCOMMITTED)

        (1)所有事务都可以看到其他未提交事务的执行结果

        (2)本隔离级别很少用于实际应用,因为它的性能也不比其他级别 好多少

        (3)该级别引发的问题是——脏读(Dirty Read):读取到了未提交的数据

    2.读取已提交 (READ COMMITTED)

        (1)这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)

        (2)它满足了隔离的简单定义:一个事务只能看见 已经提交事务所做的改变

         (3)这种隔离级别出现的问题是——不可重复读(Nonrepeatable Read):不可重复读意味着 我们在同一个事务中执行完全相同的select语句时可能看到不一样的结果。

        |——>导致这种情况的原因可能有:(1) 有一个交叉的事务有新的commit,导致了数据的改变;(2)一个数据库被多个实例操作时,同一事务的其他实例在该实 例处理其间可能会有新的commit

    3.可重复读 (REPEATABLE READ) mysql默认隔离级别

        (1)这是MySQL的默认事务隔离级别

         (2)它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行

        (3)此级 别可能出现的问题——幻读(Phantom Read):当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新 行,当用户再读取该范围的数据行时,会发现有新的幻影

        (4)InnoDBFalcon存储引擎通过多版本并发控制 (MVCCMultiversion Concurrency Control)机制解决了幻读

    4.串行化 (SERIALIZABLE)

            (1)这是最高的隔离级别

            (2)它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的 数据行上加上共享锁。

            (3)在这个级别,可能导致大量的超时现象和锁竞争

2 死锁

所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用, 它们都将无法再向前推进。 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再获得锁b的的顺序获得 锁,而在此同时又有另外一个线程B,按照先锁b再锁a的顺序获得锁

为什么会形成死锁 

两阶段锁协议(2PL官方定义: 两阶段锁协议是指所有事务必须分两个阶段对数据加锁和解锁,在对任何数据进行读、写操作之前,事务首先要获得 对该数据的封锁;在释放一个封锁之后,事务不再申请和获得任何其他封锁。 对应到 MySQL 上分为两个阶段: 1. 扩展阶段(事务开始后,commit 之前):获取锁 2. 收缩阶段(commit 之后):释放锁 就是说呢,只有遵循两段锁协议,才能实现 可串行化调度。 但是两阶段锁协议不要求事务必须一次将所有需要使用的数据加锁,并且在加锁阶段没有顺序要求,所以这种并发控 制方式会形成死锁

2.3 mysql死锁怎么解决 

MySQL有两种死锁处理方式: 

1. 等待,直到超时(innodb_lock_wait_timeout=10s)。 

2. 发起死锁检测,主动回滚一条事务,让其他事务继续执行(innodb_deadlock_detect=on)。 

手动删除死锁: mysql> show processlist;

没有看到正在执行的慢SQL记录线程,再去查看innodb的事务表INNODB_TRX,看下里面是否有正在锁定的事务线 程,看看ID是否在show full processlist里面的sleep线程中,如果是,就证明这个sleep的线程事务一直没有commit 或者rollback而是卡住了,我们需要手动kill掉。 

mysql> SELECT * FROM information_schema.INNODB_TRX; 

如果有记录,则找到trx_mysql_thread_id这个字段对应的id, 将其kill掉。假如id=100 mysql->kill 100

2.4 间隙锁 

where 后面的字段,索引条件 

1 如果where后面的字段是普通索引,就会加一个锁住[10-30)之间的数据的间隙锁 

2 如果where后面的字段是唯一键索引,就不会加任何间隙锁 

3 如果where后面的字段没有加索引,全表范围内加上间隙锁

2.5订单如何防止间隙锁:

1 尽量采用乐观锁,乐观锁是在php等代码层面的锁,就不会锁住数据库资源 

2 事务中updatewhere后面的字段尽量带上索引,不然间隙锁的范围很大 

3 尽量不要出现长事务,否则事务中更新订单时间隙锁会被锁很久,另一事务插入订单就会执行很久 

4 update订单表,begincommit之间的时间不要太长,之间不要写一些慢代码,比如请求第三方接口 

5 分表能防止不分表情况下整张表被锁住。分表后是锁住众多表中的其中一张

(0)
分享:

本文由:xiaoshu168.com 作者:xiaoshu发表,转载请注明来源!

相关阅读