程序员分享

Mysql事务与死锁

2019-06-12  本文已影响0人  文博客

好久没有写博客了,最近工作太忙了,真的是996icu呀。想找个机会跳出来。之后我要做到work life balance!

当考虑的就是数据一致性的问题时我们用就应该想到Mysql的事务。但是当我们使用事务时会有很多的坑,首先我们了解一下事务的隔离界别。

1、事物的隔离级别

数据库中有四种数据隔离级别

Read Uncommited(未提交读) 在Read Uncommited级别,事务中的修改,即便没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也成为脏读(Dirty Read)。这个级别会导致很多问题,从性能上说,Read Uncommited不会比其他的级别好太多,但缺乏其他级别的很多好处,除非真的非常有必要的理由,在实际应用中一般很少使用。

Read Commited(提交读) 大多数数据库系统的默认隔离级别都是Read Commited(Mysql除外)。Read Commited满足前面提到的个理性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个是无从开始直到提交之前,所做的任何修改对其他事务是不可见的。这个级别有时候也叫不可重复读(nonrepeatable read),因为两次执行同样的查询,可能结果的不到一样的效果。

Repeatable Read(可重复读) Repeatable Read解决了脏读的问题。该级别保证了在同一事务中多次读取同样数据的结果是一致的。但理论上,可重复读隔离级别还是无法解决另外一个幻读(Phantom Read)的问题。所谓幻读,指的是当某个事务在读某个范围内的记录时,会产生幻行(Phantom Row)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题。

Serializable(可串行化) Serializable是最高的隔离级别。他通过强制事务串行执行,避免了前面说的幻读的问题。简单地说,Serializable会在读取每一行数据上都加锁,说以可能导致大量的超时和竞争锁的问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据一致性而且可以接受没有并发的情况下,才会考虑采用该级别。

隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读
Read Uncommited YES YES YES NO
Read Commited NO YES YES NO
Repeatable Read NO NO YES NO
Serializable NO NO NO YES

2、死锁

说完隔离级别,我们看看锁的问题。

死锁是指两个或者多个事务在统一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序锁定资源时,就可能产生死锁。多个事务同时锁定同一资源时,也会产生死锁。

那么什么情况下会造成死锁?

所谓死锁<DeadLock>: 是指两个或两个以上的进程在执行过程中, 因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去. 此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等竺的进程称为死锁进程. 表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB.

例子

事务1:start transaction;
update cwb set age = 12 where id = 4 and date = '2019-05-08';
update cwb set age = 13 where id = 3 and date = '2019-05-09';
commit;事务2:start transaction;
update cwb set age = 14 where id = 3 and date = '2019-05-09';
update cwb set age = 15 where id = 4 and date = '2019-05-08';
commit;
如果凑巧,两个事务都执行了第一条update语句,更新了第一行数据,同时也锁定了该行数据,接着每个事务都尝试去执行第二条update语句,去发现该行已经被对方锁定,然后两个事务都等待对方释放锁,同时又持有对方所需要的锁,则陷入死循环。除非外部因素介入才有可能解除死锁。
上一篇 下一篇

猜你喜欢

热点阅读