mysql--锁

锁分类

    根据锁粒度和兼容性划分

                |----表锁(MyISAM,InnoDB  开销小,加锁快,不死锁,并发差)    

                        |----共享锁(S锁):加锁后其他用户可读不可写

                        |----排他锁(X锁):加锁后其他用户不可读写

                        |----意向共享锁(IS锁):innoDB中为了兼容行锁和表锁,并存多个(表级别锁)

                        |----意向排他锁(IX锁):innoDB中为了兼容行锁和表锁,只有一个(表级别锁)

                |----行锁(InnoDB  开销小,加锁快,不死锁,并发差)    

                        |----共享锁(S锁):加锁后其他用户可读不可写

                        |----排他锁(X锁):加锁后其他用户不可写但是可读(这里是快照读)!!!

                |----页面锁(BDB,各项性能居中,会出现死锁)

    根据加锁机制划分

                |----乐观锁:乐观的认为不会出现并发,手动加一个版本号用于判断(不是mvcc的那个版本号)

                |----悲观锁:行锁,表锁这些都是悲观的。

    行锁的三种算法

                |----记录锁:单个行记录上的锁

                |----间隙锁:锁定一个范围,但不包括记录本身。

                |----nextKey锁:记录锁+间隙锁,锁定一个范围,并且锁定记录本身


1.表锁:

    1.1共享读锁(S锁/共享锁)

        显式加锁:lock  table  表名  read  (local)    

        隐式加锁:select自动给涉及到所有表加读锁

        解锁:unlock tables

        加锁之后,其他用户对同一表可读不可写。

        LOCAL修饰符表示允许在其他会话中对在当前会话中获取了READ锁的的表执行插入

    1.2独占写锁(X锁/排他锁)

        显式加锁:lock  table  表名  write 

        隐式加锁:update,delete,insert自动给所涉及到的表加写锁

        解锁:unlock tables

        加锁之后,其他用户对同一表不可读写

    1.3MyISAM为什么不会出现死锁?

        MyISAM在select之前,会自动给涉及到所有表加读锁;在update,delete,insert之前,会自动给所涉及到的表加写锁。这个过程都是自动的,不需要用户使用lock table显式加锁。MyISAM总是一次获得SQL语句所需要的全部锁。这也正是MyISAM表不会出现死锁的原因。

    1.4MyISAM的并发插入

        MyISAM中的系统变量concurrent_insert,专门处理其并发插入的行为,其值可为0,1(默认值),2

        concurrent_insert = 0,不允许并发插入

        concurrent_insert = 1,如果MyISAM表中没有空洞,myisam允许在一个进程读表的同时,另一个进程从表尾插入记录

        concurrent_insert = 2,无论myisam表中有没有空洞,都允许在表尾并发插入记录

    1.5如果两个进程分别请求读锁和写锁,mysql将如何处理?

        写进程先获得锁,即使读请求先到锁等待队列,写请求后到,写锁也会插入到读锁队列。mysql认为写请求比读请求更重要。大量的更新操作会造成查询操作很难获得读锁,从而可能永远堵塞。这就是myisam不太适合于有大量更新操作和查询操作的原因

        解决方法: set  low_priority_updates  = 1    将读的优先级提高

    1.6意向共享锁(IS锁)意向排他锁(IX锁)

        仔细想想还是把意向锁放在表锁下面,原因有二:第一 意向锁是表级别的锁,第二 意向锁的作用是为了兼容表锁和行锁,刚好引出下面的行锁来。

        作用:InnoDB为了实现多粒度锁机制。兼容表锁和行锁

        举例:假如没有意向锁且行锁和表锁兼容,事务A锁住表中的一行(写锁,其他事务就不可能修改这一行),事务B锁住整个表(写锁,B可就以随便修改表内数据),这样事务A,事务B是相悖的

        意向锁如何实现行锁和表锁兼容?:还是上面的例子,事务A申请行锁(写锁),数据库会自动先给事务A申请表的意向排他锁。当事务B去申请表的写锁时就会失败,因为表上有意向排他锁之后事务B申请表的写锁时会被阻塞

        如果一个事务请求的锁模式与当前的锁兼容,InnoDB就请求的锁授予该事务;反之,如果两者两者不兼容,该事务就要等待锁释放。 意向锁是InnoDB自动加的,不需用户干预。对于update、delete和insert语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通select语句,InnoDB不会加任何锁。

        意向锁是表级别锁。假如此时你要加一个表锁,意向锁如果是行级别锁则需要遍历全表

2.行锁:

        InnoDB行锁是给索引上的索引项加锁来实现的。只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁

    2.1共享锁(S锁)

        显式加锁:select ... LOCK IN SHARE MODE

        隐式加锁:innoDB的select不会加任何锁(这是快照读,详情参考mvcc)

        加锁之后,其他用户对同一行可读不可写

    2.2排他锁(X锁)    

        显式加锁:select ... FOR UPDATE

        隐式加锁:innoDB的update,delete,insert操作自动给所涉及到的表加排他锁

        加锁之后,其他用户对同一行不可写但是可读(因为innoDB的select默认是快照读,不上锁)

    2.3记录锁(Record Locks)

        记录锁就是为某行记录加锁,它封锁该行的索引记录

    SELECT * FROM table WHERE id = 1 FOR UPDATE;

        id 列必须为唯一索引列或主键列,查询语句必须为精准匹配(=),不能为 >、<、like等。否则上述语句加的锁就会变成临键锁。

    2.4间隙锁(GAP锁)

        当我们用范围条件检索数据并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加记录锁;对于键值在条件范围内但并不存在的记录,InnoDB也会对其加锁,这就是间隙锁 

        举例:下图为表数据和索引B的数据结构,事务A拿到了X锁。事务B要修改数据。

        事务A:select * from z where b=6 for update 

        事务B:update z set b=7 where id=7 (阻塞)

                     update z set id=6 where id=8 (阻塞)

        我们可以看到,不管是将b修改为7还是将id修改为8,都在锁住的范围内

    2.5临键锁(next-key锁)

        我们可以将next-key理解为一种特殊的算法

        Next-Key = 记录锁 + 间隙锁     

        作用:1.和mvcc一起解决幻读的问题    2.满足复制,备份需要

        假如不使用间隙锁,其它事务插入了empid大于100的记录,那么本事务再次执行上述语句,前后两次结果不一致就会发生幻读。

        mysql的恢复机制是按照事务提交的顺序记录sql语句(执行binlog中的sql语句),说白了,还是不允许出现幻读的情况

    2.6行锁争用情况

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

3.死锁:

3.1什么是死锁?

        多个事务在同一资源上互相占用形成回路。这就是死锁

3.2死锁的例子

        下面是一个死锁的例子,事务A想修改id=2的数据,但是必须要事务B释放。事务B想要修改id=1的数据,同样也在等待事务A的结束。

        t1时刻 A事务执行:select * from test where id=1 for update;

        t2时刻 B事务执行:  select * from test where id=2 for update;

        t3时刻 A事务执行:update test set id=id where id=2;

        t4时刻 B事务执行:update test set id=id where id=1;

3.3解决方法:

        部分或完全回滚其中一个事务( InnoDB默认回滚最少行级排他锁的事务)

3.4预防手段:

        1.innodb_lock_wait_timeout  InnoDB的锁超时等待参数

        2.合理设计索引

        3.降低隔离级别(看业务是否允许)

        4.大事务拆小,尽量一次性把锁拿全 

3.5定位死锁:

        1.查看隔离级别    select @@tx_isolation;        

        2.查看当前线程    show processlist;

        3.show innodb status:  返回结果中包括死锁相关事务的详细信息,如引发死锁的 SQL 语句,事务已经获得的锁,正在等待什么锁,以及被回滚的事务等。据此可以分析死锁产生的原因和改进措施。

        4.重要的三张锁的监控表innodb_trx,innodb_locks,innodb_lock_waits

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,753评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,668评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,090评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,010评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,054评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,806评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,484评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,380评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,873评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,021评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,158评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,838评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,499评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,044评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,159评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,449评论 3 374
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,136评论 2 356

推荐阅读更多精彩内容