1. 什么是死锁
- 死锁就是两个以上线程互相竞争资源导致相互等待的现象
- 发生死锁有四个条件:互斥、请求与保持条件、不可抢占、循环等待
2. 举个栗子:
- 环境:MYSQL 8.0+,默认隔离级别RR
- 表存在主键索引和仅name字段的普通索引
2.1. 栗子一:
- 事务A将id=1的余额字段减100金额,然后对id=2的余额字段加100金额
- 在两个操作中间时刻,事务B对id=2的余额减300金额,又对id=1的余额加300

- 事务A在执行第二条update语句时,需要等待事务B释放id=2的行锁
- 事务B在执行第二条update语句时,需要等待事务A释放id=1的行锁
- 所以就发生了死锁
2.1.1 代码栗子:
@PutMapping("/dead/lock")
public BaseResponse deadLock() {
CompletableFuture.runAsync(() -> userAccountService.deadLock());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
userAccountService.mockOtherTransactional();
return BaseResponse.SUCCESS();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deadLock() {
try {
UserAccount account = this.getById(1L);
BigDecimal decimal = account.getAmount().subtract(new BigDecimal("100"));
this.updateAmountById(account.getId(), decimal);
TimeUnit.SECONDS.sleep(5);
UserAccount account2 = this.getById(2L);
BigDecimal decimal2 = account2.getAmount().add(new BigDecimal("100"));