十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
行锁的等待
在成都网站建设、网站制作过程中,需要针对客户的行业特点、产品特性、目标受众和市场情况进行定位分析,以确定网站的风格、色彩、版式、交互等方面的设计方向。成都创新互联公司还需要根据客户的需求进行功能模块的开发和设计,包括内容管理、前台展示、用户权限管理、数据统计和安全保护等功能。
在介绍如何解决行锁等待问题前,先简单介绍下这类问题产生的原因。产生原因简述:当多个事务同时去操作(增删改)某一行数据的时候,MySQL 为了维护 ACID 特性,就会用锁的形式来防止多个事务同时操作某一行数据,避免数据不一致。只有分配到行锁的事务才有权力操作该数据行,直到该事务结束,才释放行锁,而其他没有分配到行锁的事务就会产生行锁等待。如果等待时间超过了配置值(也就是 innodb_lock_wait_timeout 参数的值,个人习惯配置成 5s,MySQL 官方默认为 50s),则会抛出行锁等待超时错误。
如上图所示,事务 A 与事务 B 同时会去 Insert 一条主键值为 1 的数据,由于事务 A 首先获取了主键值为 1 的行锁,导致事务 B 因无法获取行锁而产生等待,等到事务 A 提交后,事务 B 才获取该行锁,完成提交。这里强调的是行锁的概念,虽然事务 B 重复插入了主键,但是在获取行锁之前,事务一直是处于行锁等待的状态,只有获取行锁后,才会报主键冲突的错误。当然这种 Insert 行锁冲突的问题比较少见,只有在大量并发插入场景下才会出现,项目上真正常见的是 updatedelete 之间行锁等待,这里只是用于示例,原理都是相同的。
三、产生的原因根据我之前接触到的此类问题,大致可以分为以下几种原因
for update 的作用是在查询的时候为行加上排它锁,当一个事务的操作未完成时候,其他事务可以读取但是不能写入或更新。
它的典型使用场景是 高并发并且对于数据的准确性有很高要求 ,比如金钱、库存等,一般这种操作都是很长一串并且开启事务的,假如现在要对库存进行操作,在刚开始读的时候是1,然后马上另外一个进程将库存更新为0了,但事务还没结束,会一直用1进行后续的逻辑,就会有问题,所以需要用for upate 加锁防止出错。
行锁的具体实现算法有三种:record lock、gap lock以及next-key lock。
只在可重复读或以上隔离级别下的特定操作才会取得 gap lock 或 next-key lock,在 Select、Update 和 Delete 时,除了基于唯一索引的查询之外,其它索引查询时都会获取 gap lock 或 next-key lock,即锁住其扫描的范围。主键索引也属于唯一索引,所以主键索引是不会使用 gap lock 或 next-key lock
for update 仅适用于InnoDB,并且必须开启事务,在begin与commit之间才生效。
select 语句默认不获取任何锁,所以是可以读被其它事务持有排它锁的数据的!
InnoDB 既实现了行锁,也实现了表锁。
当有明确指定的主键/索引时候,是行级锁,否则是表级锁
假设表 user,存在有id跟name字段,id是主键,有5条数据。
明确指定主键,并且有此记录,行级锁
无主键/索引,表级锁
主键/索引不明确,表级锁
明确指定主键/索引,若查无此记录,无锁
参考博文:
是这样的 你 select * from xx where id=xx for update
数据库会给你改成
begin;
select * from xx where id=xx for update
commit;
这个是叫做 隐式提交。--mysql有很多隐式提交的语句的
所以如果你要显式提交事务的话
你得手动 在select * from xx where id=xx for update 语句之前,输入begin;
等你想结束的时候commit/rollback就行了