数据库的锁机制

mysql如何处理脏写的

  mysql处理写并发,说白了就是靠的锁机制,让多个事务对一行数据执行写操作的时候串行化,避免同时写一行数据。如果现在有一个事务来了要更新这行数据,它会先看看这行数据此时有没有人加锁?一看没人加锁,太好了,说明他是第一个人,捷足先登了。此时这个事务就会创建一个锁,里面包含了自己的trx_id和等待状态,然后把锁跟这行数据关联在一起。

  

  现在有另外一个事务B过来了,也想更新那行数据,此时就会检查一下,当前这行数据有没有别人加锁。然而他一下子发现,事务A居然抢先给这行数据加锁了,这怎么办呢?事务B这个时候一想,那行,我也加个锁,然后等着排队不就得了,这个时候事务B也会生成一个锁数据结构,里面有他的trx_id,还有自己的等待状态,但是他因为是在排队等待,所以他的等待状态就是true了。

  

  接着事务A这个时候更新完了数据,就会把自己的锁给释放掉了。锁一旦释放了,他就会去找,此时还有没有别人也对这行数据加锁了呢?他会发现事务B也加锁了。于是这个时候,就会把事务B的锁里的等待状态修改为false,然后唤醒事务B继续执行,此时事务B就获取到锁了。

  

共享锁和独占锁

  刚才上面提到的锁实际上就是Exclude独占锁,当有一个事务加了独占锁之后,此时其他事务再要更新这行数据,都是要加独占锁的,但是只能生成独占锁在后面等待。但是可以读,因为读是没有锁的,通过mvcc直接读取快照数据。

  

共享锁:LOCK in SHARE MODE 独占锁:for UPDATE

读锁能够对读请求共享,写锁具有排他性。
(1)当我们对一行数据开启事务后加读锁,我们还能再次加读锁;若是加写锁就会因为锁占用而出现等待,只有事务commit后才能加锁。

  

 (2) 我们对一行数据加写锁后,只有事务commit后才能加其他锁(读锁/写锁)。

  

于是可以总结出如下规律:

  

死锁

  比如这两个事务,都在等待对方事务执行完毕才能获取到当前记录的锁。此时就会陷入等待状态造成死锁。这种情况一般有以下策略:
  1. 直接进入等待,直到超时。innodb_lock_wait_timeout 默认是 50S,也就是说被锁住的线程 50S 之后才会超时退出、然后被其他线程执行。你也可以设置短一点、比如 5S 左右,不过这种方法一般都不会用。
  2. 将参数 innodb_deadlock_detect 设置为 on(默认已开启),就是说发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。只是这样比较消耗cpu。
  3. 控制并发、减少事务并行。
  4. 优化sql,尽量保证sql一次只会持有一条数据的锁。

原文地址:https://www.cnblogs.com/wlwl/p/14450371.html