锁的认识
场景: 一个很久没有改动的访问量较低系统,由于访问增大忽然出现了一个问题,经过日志查看和代码排查发现原因如下
- 表 A 主键:id,状态:status , 姓名: name
- 表 B 主键:id,版本号:version ,累积总额:total
-- 小明 --
start transaction;
-- …… --
update A set status = 2 where id= 1 and status =1;
update B set total = total + XXX1 where id = 1 and version = 1;
commit;
-- 小红 --
start transaction;
-- …… --
update A set status = 2 where id= 2 and status =1;
update B set total = total + XXX2 where id = 1 and version = 1;
commit;
-- 张三 --
start transaction;
……
update A set status = 2 where id= 3 and status =1;
update B set total = total + XXX3 where id = 1 and version = 1;
commit;
表 A 的更新操作是用户订单状态完成的更新,表 B 的更新操作是业务上的统计
很明显当并发产生时(多个事务去操作表 B 同一行数据)表 B 的更新会被乐观锁 version 控制住然后代码里判定更新失败并且抛出异常导致用户表A的更新被回滚
问题不在于用了乐观锁,而是在于不相干的两个业务放到了一个事务里,统计和订单状态更新应该剥离开去做
上面的问题导致了部分订单支付完成消息消费的延迟,重复很多次才被消费到,间隔时间较长,用户觉得已经扣款了订单为什么还没有成功
总结一下 MySQL 中 InnoDB 的几种锁以及应用场景:
mysql> show variables like '%isolation%';
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.11 sec)
MySQL 中 InnoDB 的事务隔离级别基本都是可重复度(REPEATABLE-READ)
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.17 |
+-----------+
1 row in set (0.01 sec)
根据数据库的版本号在MySql官网找到InnoDB的锁
锁的解释
锁:计算机协调多个进程或线程并发访问某一资源的机制
锁的重要性
在数据库中,除了传统的计算资源(CPU、RAM、I\O等)的争抢,数据也是一种供多用户共享的资源
因此,如何保证数据并发访问的一致性,有效性,是所有数据库必须要解决的问题
锁冲突也是影响数据库并发访问性能的一个重要因素,因此锁对数据库尤其重要
锁的缺点
加锁是消耗资源的,锁的各种操作,包括:获得锁、检测锁是否已经解除、释放锁等,都会增加系统的开销
网友评论