1.乐观锁和悲观锁(5分钟)
tableA:
| id | name | money |
|---|---|---|
| 1 | A | 1000 |
并发情况下要实现扣除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
结论:
RC:在聚集索引上加X锁
RR:在聚集索引上加X锁
情况二: id是唯一索引+RC/RR
结论:
RC:在聚集索引上加X锁,辅助索引上加X锁
RR:在聚集索引上加X锁,辅助索引上加X锁
情况三: id是非唯一索引
在RC下:
在RR下:
结论:
RC:在聚集索引上加X锁,辅助索引上加X锁
RR:在聚集索引上加X锁,辅助索引上加X锁+间隙锁=临键锁
情况四: id无索引
在RC下:
在RR下:
(注:对于不满足查询条件的记录,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)使用低隔离级别