mysql锁

本文深入解析MySQL中的乐观锁与悲观锁机制,包括共享锁、排它锁、行锁及表锁的概念与应用场景,并探讨不同锁类型对并发性能的影响。

参考文章:https://blog.youkuaiyun.com/puhaiyang/article/details/72284702

一.mysql锁的结构图


如上图所示,针对mysql的innodb存储引擎,mysql锁包括了乐观锁和悲观锁。而悲观锁又包括共享锁和排它锁,共享锁/排它锁里又有行锁和表锁的实现,下面一个个说明他们的内容。

二.锁详解

1.乐观锁

乐观锁不是数据库自带的,需要我们自己去实现。乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去判断是否有冲突了。

通常实现是这样的:在表中的数据进行操作时(更新),先给数据表加一个版本(version)字段,每操作一次,将那条记录的版本号加1。然后update的时候,where子句里,增加version值的判断,如果update返回的值是0,说明是版本号冲突,如果是1,则更新成功。

举个例子,例如要更新一个用户的数据

(1)查出用户的数据(假设根据uid查询),sql为:select id,name,mobile,version from user_db.t_user_info where uid=1024;

假设查出来的数据为


(2)假设要更新name字段为lisi,则sql为:update user_db.t_user_info set name='lisi',version=4 where uid=1024 and version=3;

如果这时候更新的结果是1,则更新成功;如果为0,则需要用户重新操作

2.悲观锁

悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作,这点跟java中的synchronized很相似,所以悲观锁需要耗费较多的时间。另外与乐观锁相对应的,悲观锁是由数据库自己实现了的,要用的时候,我们直接调用数据库的相关语句就可以了。

mysql的悲观锁包括共享锁和排它锁。

先简单介绍什么是共享锁和排它锁:共享锁指的就是对于多个不同的事务,对同一个资源共享同一个锁;而排它锁与共享锁相对应,就是指对于多个不同的事务,对同一个资源只能有一把锁。

举个简单形象的例子来说明一下:共享锁就像是你家的大门钥匙,除了你有,你家人也有;而排它锁则像是试衣间,我进来了别人就不能进来了。

再来说说什么是行锁和表锁。

顾名思义,行锁获取数据库某一行的锁,而表锁就是获取某张表的锁。

下面更详细说明他们的用法。

(1)共享锁

刚刚说了,对于悲观锁,一般数据库已经实现了,共享锁也属于悲观锁的一种,所以,mysql自身对共享锁的功能是有实现的。

A.对于共享锁来说,一个事务获取了某一行的共享锁,则其他事务还可以继续获取这一行的共享锁,但是不能获取这行的排它锁。

B.如何获取某一行/表的共享锁。在select语句后面加 lock in share mode,即可获取共享锁。例如,sql为:

begin;
SELECT * from city where id = "1"  lock in share mode;

C.值得注意的一点,在有事务获取了共享锁之后,其他事务是不能做insert/update/delete,因为insert/update/delete语句,是自动加上排它锁的

D.如何判断获取的是行锁还是表锁

SELECT * from city where id = "1"  lock in share mode; 这个sql里,如果id这个字段带了索引,则获取的是行锁,否则获取的是表锁

ps:共享锁又称读锁

(2)排它锁

mysql自身对排它锁的功能也是有实现的

A.对于排它锁来说,一个事务获取了某一行的共享锁,其他事务不能再获取任何锁(包括共享锁和排它锁)

B.如何获取某一行/表的排它锁。在select语句后面加 for update,即可获取排它锁。例如,sql为:

begin;

SELECT * from city where id = "1"  lock in share mode;

C.如何判断获取的是行锁还是表锁和共享锁是一样的

D.insert/update/delete语句,是自动加上排它锁的

ps:排它锁又称写锁

(3)行锁

行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。

虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。

使用行级锁定的主要是InnoDB存储引擎。

(4)表锁

表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。

当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并大度大打折扣。


关于行锁和表锁,前面在共享锁和排它锁里已有说明,这里只提一点,慎用表锁,即select for update语句,where子句务必带上索引否则极容易造成性能问题

### MySQL 机制详解 MySQL 中的机制是为了保障数据库在高并发环境下的数据一致性和稳定性而设计的重要功能之一。以下是关于 MySQL 机制的具体解析: #### 1. 的分类 MySQL 主要分为两种类型的:表级和行级。 - **表级 (Table-Level Lock)** 表级是最简单的定策略,适用于 MyISAM 存储引擎。它会在整个表上施加,无论是读操作还是写操作都会影响到整张表。对于 `SELECT` 操作,MyISAM 会自动给涉及的所有表加上读;而对于 `UPDATE`, `INSERT`, 和 `DELETE` 则会自动加上写[^3]。 - **行级 (Row-Level Lock)** 行级由 InnoDB 存储引擎实现,提供更高的并发能力。只有涉及到具体记录的操作才会触发行级。例如,在执行 `SELECT ... FOR UPDATE` 或者 `SELECT ... LOCK IN SHARE MODE` 时,InnoDB 只会对符合条件的特定行加而不是封整个表[^2]。 #### 2. 不同存储引擎的特性 不同的存储引擎有不同的行为: - **MyISAM**: 默认使用的是表级别的,这意味着即使是一个小范围内的更新也会阻塞其他线程对该表任何部分的访问[^3]。 - **InnoDB**: 支持事务以及更细粒度的行级,这使得它可以更好地处理复杂的多用户场景下的并发请求[^4]。 #### 3. 常见类型及其作用 除了基本的表级与行级区分外,还有几种具体的形式用于满足不同需求: - **共享 (Shared Lock, S-Lock)** 当一个客户端通过命令如 `LOCK TABLES table_name READ` 获取了一个表上的共享之后,其它客户也可以获得该表上的共享,但不能再获取排他直到当前持有共享的所有连接释放它们为止[^2]。 - **排他 (Exclusive Lock, X-Lock)** 排他允许独占式的修改权限。如果某个事务已经获得了某条记录或者某些列上的排他,则在此期间不允许别的事务再对此同一组资源申请任何形式的新——既包括另外的排他也包括新的共享[^2]。 - **GAP ** 这种特殊的用来阻止新纪录插入到现有两条连续记录之间的空隙(gap)里去。比如当我们运行下面这条SQL语句的时候就会用到gap lock:`SELECT * FROM table_name WHERE id > 10 FOR UPDATE;` - **Next-Key Lock** 是一种组合了索引记录本身(record)和其前面那个区间(gap)两者一起保护起来的一种复合型模式。主要用于解决可重复读(repeatable read)隔离级别下可能出现的幻影问题(phantom problem)[^4]。 #### 4. 死现象及预防措施 死是指两个或更多事务相互等待对方持有的资源从而进入僵局的状态。为避免这种情况发生可以采取以下方法: - 尽量按照固定的顺序访问资源; - 减少单次事务持续时间; - 设置合理的超时参数让系统能够及时发现并终止潜在的死循环状况等等[^4]。 ```sql -- 示例:如何手动解表 UNLOCK TABLES; ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值