悲观锁-乐观锁-行锁-表锁-共享锁-排他锁-公平锁

3次阅读

共计 2305 个字符,预计需要花费 6 分钟才能阅读完成。

前言

关键词:乐观锁,乐观锁,表级锁,行级锁,共享锁,排他锁,偏心锁,非偏心锁

乐观锁

每次获取数据的时候放心数据被批改, 所以每次获取数据的时候都会进行加锁, 确保本人应用过程中数据不会被他人批改, 应用实现后对数据进行解锁. 因为数据进行加锁, 期间对改数据进行读写的其余线程都会进行期待

CREATE TABLE `tb_goods_stock` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `goods_id` bigint(20) unsigned DEFAULT '0' COMMENT '商品 ID',
  `nums` int(11) unsigned DEFAULT '0' COMMENT '商品库存数量',
  `create_time` datetime DEFAULT NULL COMMENT '创立工夫',
  `modify_time` datetime DEFAULT NULL COMMENT '更新工夫',
  PRIMARY KEY (`id`),
  UNIQUE KEY `goods_id` (`goods_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品库存表';

将商品库存数量 nums 字段类型设为 unsigned,保障在数据库层面不会产生正数的状况。

留神,应用乐观锁,须要 敞开 mysql 的 主动提交性能,将 set autocommit = 0;

留神,mysql 中的行级锁是 基于索引 的,如果 sql 没有走索引,那将应用表级锁把 整张表锁住

1、开启事务,查问要卖的商品,并对该记录加锁。

begin;
select nums from tb_goods_stock where goods_id = {$goods_id} for update;

2、判断商品数量是否大于购买数量。如果不满足,就 回滚事务

3、如果满足条件,则缩小库存,并 提交事务

update tb_goods_stock set nums = nums - {$num} where goods_id = {$goods_id} and nums >= {$num};
commit;

begin tran 示意开始事务,

commit tran 示意提交事务,

rollback tran 示意回滚事物

乐观锁

乐观锁,简略地说,就是从利用零碎层面上做并发管制,去加锁。

实现乐观锁常见的形式:版本号 version

实现形式,在数据表中减少版本号字段,每次对一条数据做更新之前,先查出该条数据的版本号,每次更新数据都会对版本号进行更新。在更新时,把之前查出的版本号跟库中数据的版本号进行比对,如果雷同,则阐明该条数据没有被批改过,执行更新。如果比对的后果是不统一的,则阐明该条数据曾经被其他人批改过了,则不更新,客户端进行相应的操作揭示。

1、查问要卖的商品,并获取版本号。

begin;
select nums, version from tb_goods_stock where goods_id = {$goods_id};

2、判断商品数量是否大于购买数量。如果不满足,就回滚事务。

3、如果满足条件,则缩小库存。(更新时判断 以后 version 与第 1 步中获取的 version 是否雷同)

update tb_goods_stock set nums = nums - {$num}, version = version + 1 where goods_id = {$goods_id} and version = {$version} and nums >= {$num};

4、判断更新操作是否胜利执行,如果胜利,则提交,否则就回滚。

实用场景

乐观锁

比拟适宜写入操作比拟频繁的场景, 如果呈现大量的读取操作, 每次读取的时候都会进行加锁, 这样会减少大量的锁的开销, 升高了零碎的吞吐量

乐观锁

比拟适宜读取操作比拟频繁的场景, 如果呈现大量的写入操作, 数据发生冲突的可能性就会增大, 为了保证数据的一致性, 应用层须要一直的从新获取数据, 这样会减少大量的查问操作, 升高了零碎的吞吐量

行锁

拜访数据库的时候 针对整个行数据

主动加锁。对于 UPDATE、DELETE 和 INSERT 语句,InnoDB 会主动给波及数据集加排他锁;对于一般 SELECT 语句,InnoDB 不会加任何锁。

表锁

拜访数据库的时候 针对整个表数据

主动加锁。查问操作(SELECT),会主动给波及的所有表加读锁,更新操作(UPDATE、DELETE、INSERT),会主动给波及的表加写锁。
<!––>

共享锁(读锁)和排他锁(写锁)

共享锁(S 锁):共享 (S) 用于不更改或不更新数据的操作(只读操作),如 SELECT 语句。

如果事务 T 对数据 A 加上共享锁后,则其余事务只能对 A 再加共享锁,不能加排他锁。获准共享锁的事务 只能读数据,不能批改数据。

排他锁(X 锁):用于数据批改操作,例如 INSERT、UPDATE 或 DELETE。确保不会同时同一资源进行多重更新。

如果事务 T 对数据 A 加上排他锁后,则其余事务不能再对 A 加任任何类型的封闭。获准排他锁的事务既能读数据,又能批改数据。

偏心锁 非偏心锁

锁的偏心与非偏心,是指线程申请获取锁的过程中,是否容许插队

在偏心锁上,线程将按他们发出请求的程序来取得锁;而非偏心锁则容许在线程发出请求后立刻尝试获取锁,如果可用则可间接获取锁,尝试失败才进行排队期待。

ReentrantLock 提供了两种锁获取形式,FairSyn 和 NofairSync。论断:ReentrantLock 是以独占锁的加锁策略实现的互斥锁,同时它提供了偏心和非偏心两种锁获取形式。

下一期讲讲 偏差锁、轻量级锁、自旋锁、重量级锁

创作不易, 如果本篇文章能帮忙到你, 请给予反对, 赠人玫瑰, 手有余香,虫虫蟹蟹观众姥爷了

正文完
 0