mysql Innodb锁应用

59 阅读2分钟

1.乐观锁和悲观锁(5分钟)
tableA:

idnamemoney
1A1000  

并发情况下要实现扣除100元?

 1.乐观锁实现:   

    begin;
         select version from tableA where id=1; (在RC和RR中是快照读)              
         update tableA set money=money-100,version=@version+1 where id=1 and version=@version;
    commit;

      

 2.悲观锁实现:

    begin;
         select * from tableA where id=1 for update;//加X锁,退化成串行读                   update tableA set money=money-100 where id=1;
   commit;

3.行锁实现:    

      begin;  
        select money from tableA where id=1;  
        update tableA set money=money-100 where id=1 and money=@money;
     commit;  

    2.分析delete from t1 where id = 1加什么锁?(hedengcheng.com/?p=771)

判断怎么加锁,需要两个大前提:

1、在什么事务隔离级别下

2、条件是什么索引

分析:       

前提一: id列是不是主键?

前提二: 当前系统的隔离级别是什么?

前提三: id列如果不是主键,那么id列上是否有索引?

前提四: id列上如果有二级索引,那么这个索引是唯一索引吗?

情况一: id列是主键+RC/RR

  image.png

 结论:

      RC:在聚集索引上加X锁

      RR:在聚集索引上加X锁

    情况二: id是唯一索引+RC/RR

    image.png

结论:

      RC:在聚集索引上加X锁,辅助索引上加X锁

      RR:在聚集索引上加X锁,辅助索引上加X锁

   情况三: id是非唯一索引

  在RC下:

image.png

在RR下:

image.png       结论:  

      RC:在聚集索引上加X锁,辅助索引上加X锁

      RR:在聚集索引上加X锁,辅助索引上加X锁+间隙锁=临键锁

   情况四: id无索引

   在RC下:

   image.png

  在RR下:   image.png (注:对于不满足查询条件的记录,innodb会提前放锁)

 结论:
RC:全部聚集索引加X锁
RR:全部聚集索引加X锁和Gap锁

3.怎么分析死锁
死锁形成的原因:锁通常是逐步获得的,这就决定了在InnoDB中发生死锁的可能。
简单例子(在RR下,id是主键的情况下):

 

事务A事务B
begin;
update tableA set name=B where id=1;//对id=1加X锁
update tableA set name=B where id=2;//对id=2加X锁
update tableA set name=B where id=2;//阻塞,申请对id=2加X锁
update tableA set name=B where id=1;//阻塞,申请对id=1加X锁 查看死锁日志:     show engine innodb status;

日志里的锁说明:

lock_mode X locks rec but not gap Record lock:X 间隙锁

lock_mode X Record lock:记录锁+间隙锁=next-key锁

lock_mode X locks gap before rec insert intention:意向锁

4.怎么避免死锁
(1)尽量保持事务简短(操作的数据集小、事务执行时间短等),减少锁竞争的概率
(2)避免事务中加入用户交互或远程调用等耗时操作
(3)批处理的事务尽量做到数据隔离,如做数据清理时清理的数据最好是用户等其它事务不会访问到的
(4)使用低隔离级别