表级锁 行级锁
从 锁的粒度 来分, 分为 表级锁 和 行级锁
-
表级锁: 一般是存储引擎不支持行锁时才使用
-
行级锁: 当SQL语句对记录进行读写操作时, 可以选择对记录加行锁
- 正经记录锁: 最常用的行级锁, 仅仅把一条记录锁上
- gap锁: 会锁住 该记录与上一记录的间隙
- next-key锁: 会锁住 该记录 和 该记录与上一记录的间隙
- 加S型next-key锁: select * from table where id>1 and id<=6 lock in share mode;
- 加X型next-key锁: select * from table where id>1 and id<=6 lock for update;
- 插入意向锁: 表明有事务想在某个间隙插入新记录, 但现在处于等待状态
共享锁 独占锁 意向锁
从 锁的模式 来分, 分为 共享锁, 独占锁, 意向锁
- 共享锁 (Share): 简称S锁, 行级或表级, 允许所有事务读取该记录, 但不允许修改
- 哪些语句会自动加S锁: 无
- 怎么手动加S锁:
- 对读取的记录行加S锁: select … lock in share mode;
- 对整张表加S锁: lock tables t read;
- 独占锁 (Exclusive): 简称X锁, 行级或表级, 只允许本事务读写该记录
- 哪些语句会自动加X锁: update, delete, insert
- 怎么手动加X锁:
- 对读取的记录行加X锁: select … for update;
- 对整张表加X锁: lock tables t write;
- 共享意向锁: 简称IS锁, 是表级锁, 仅用来判断表中是否有记录上了S锁
- 独占意向锁: 简称IX锁, 是表级锁, 仅用来判断表中是否有记录上了X锁
- 自增锁: 用于给auto_increment字段递增赋值, 只作用于单个插入语句, 插入完成后立刻释放
注: 普通的select语句不加任何锁, 根据 隔离级别的不同, 会读取记录的最新版本 或 MVCC版本链记录
悲观锁 乐观锁
从 锁的风格 来看, 分为 悲观锁 和 乐观锁
- 悲观锁: 每次获取数据的时候,都默认别人会修改这个数据,所以都会上锁,这样就会阻止其他人访问该数据,直到事务结束才释放锁
# 原生SQL
begin;
select stock from tb_sku where id=1 for update;
update tb_sku set stock=2 where id=1;
commit;
# ORM
sku = SKU.objects.select_for_update().get(id=1)
sku.stock=2
sku.save()
- 乐观锁: 每次获取数据的时候,都默认别人不会修改这个数据,所以不会加锁,只有在更新的时候会判断在此期间这个数据是否被更改
# 原生SQL
select stock from tb_sku where id=1; # 假设这里查到库存为7
# 判断下单数量 是否大于 库存
update tb_sku set stock=2 where id=1 and stock=7;
# ORM
SKU.objects.filter(id=1, stock=7).update(stock=2)