锁
表锁
加锁后需要主动释放 unlock tables
S锁, 也叫做读锁, 共享锁, 对应于我们常用的 lock table table_name read
X锁, 也叫做写锁, 排他锁, 对应于我们常用的 lock table table_name write
行锁
事务提交后, 会自动释放锁
S锁, 也叫做读锁, 共享锁, 对应于我们常用的 select from users where id =1 lock in share mode
X锁, 也叫做写锁, 排他锁, 对应于我们常用的 select from users where id =1 for update
| S | X | |
|---|---|---|
| S | 兼容 | 冲突 |
| X | 冲突 | 冲突 |
X锁又分为: 行锁(record lock), 间隙锁(gap lock), 临界锁(next-key lock)
在做更新操作时(insert, update, delete, select for update), mysql会对扫描到的记录加行锁
除了通过唯一索引等值匹配, mysql还会对扫描到的行加间隙锁, 此时就形成了临界锁(行锁 + 间隙锁)
死锁案例一
伪代码
@Transactionalpublic void upsert(Entity entity) {Entity exists = mapper.select(entity.getId())if(exists != null) {mapper.update(entity);return;}try {mapper.insert(entity);} catch(DuplicateKeyException e) {mapper.update(entity)}}
复现步骤
- 目标记录在数据库中不存在
- 3个线程同时执行该方法, 并且在执行第3行代码时, 查出来的记录都是空
- 进而, 3个线程都尝试向数据库中插入目标记录, 这时只有一个线程会执行成功, 并结束返回
- 另外2个线程则会插入失败, 捕获到重复键异常, 这时它们都会对目标记录加上S锁
- 之后, 这2个线程又会去更新目标记录, 在更新的之前, 会先申请目标记录的X锁, 此时就出现了死锁
查看锁相关信息
show engine innodb status;select * from information_schema.innodb_trx;select * from information_schema.innodb_locks;select * from information_schema.innodb_lock_waits;
