TDSQL Boundless 悲观事务

悲观锁是一种数据库并发控制机制,其核心思想是先取锁,再访问。它假设在多用户并发环境下,数据冲突的概率很高,因此在访问数据之前,先对数据加锁,以防止其他事务修改或读取数据,从而确保数据的一致性。

相关产品
TDSQL Boundless 产品页,含版本规格、价格与购买入口。

一、悲观锁的基本概念

悲观锁的特点是具有强烈的独占性和排他性。当事务需要对数据进行操作时,它会先获取锁,确保在事务执行期间,其他事务无法修改这些数据。这种机制适用于数据竞争激烈的场景,能够有效避免脏读、幻读和不可重复读等并发问题。

与乐观锁相比,悲观锁采取了一种更为保守的策略。乐观锁假设冲突很少发生,在提交操作时才检查冲突;而悲观锁则假设冲突经常发生,提前预防冲突。

二、悲观锁的实现方式

TDSQL Boundless 中的悲观锁主要通过以下两种 SQL 语句实现:

三、排他锁(SELECT … FOR UPDATE)

排他锁(Exclusive Lock),也称为写锁,是最常用的悲观锁实现方式。使用SELECT … FOR UPDATE语句可以对查询到的数据行加排他锁,阻止其他事务对这些数据行进行修改或加锁。

START TRANSACTION;SELECT * FROM orders WHERE id = 1 FOR UPDATE;– 对查询到的数据进行操作UPDATE orders SET status = 'shipped' WHERE id = 1;COMMIT;

在此示例中,当事务 A 执行SELECT … FOR UPDATE后,其他事务如果尝试对同一数据行执行SELECT … FOR UPDATE或修改操作,将会被阻塞,直到事务 A 提交或回滚。

四、共享锁(SELECT … LOCK IN SHARE MODE)

共享锁(Shared Lock),也称为读锁,使用SELECT … LOCK IN SHARE MODE语句可以对查询到的数据行加共享锁。共享锁允许多个事务同时读取同一数据行,但会阻止任何事务对数据行进行修改。

START TRANSACTION;SELECT * FROM products WHERE id = 1 LOCK IN SHARE MODE;– 其他事务可以读取但不能修改这些数据COMMIT;

共享锁适用于需要确保数据在读取期间不被修改,但允许多个事务同时读取的场景。

五、悲观锁的锁粒度

TDSQL Boundless 的存储引擎支持行级锁,但实际锁的粒度取决于查询条件是否使用了索引。如果 WHERE 子句中的条件字段有索引,TDSQL Boundless 会使用行级锁;如果没有索引,则可能升级为范围锁。

— 创建表CREATE TABLE users ( user_id INT PRIMARY KEY, username VARCHAR(20));SELECT * FROM users WHERE user_id = 101 FOR UPDATE; — 行级锁SELECT * FROM users WHERE username = 'john' FOR UPDATE; — 范围锁(username 列无索引,锁整张表的数据)SELECT * FROM users WHERE user_id >= 100 AND user_id < 200 FOR UPDATE; — 范围锁(只锁 user_id 在 [100, 200) 区间的数据

六、与 MySQL (InnoDB) 悲观锁行为差异的对比

TDSQL Boundless 与 MySQL (InnoDB) 的悲观锁核心差异源于二者架构设计:

·MySQL (InnoDB) 的锁是面向物理存储的,锁信息记录的是数据行在磁盘上的“门牌号”(哪个表空间、哪个页、哪一行)。这在其单机顺序存储的背景下非常高效。

·TDSQL Boundless 的锁是面向逻辑键值的,锁信息记录的是数据行的“身份证号”(主键值)。这种设计与它的分布式、散列存储架构天然契合,使得锁管理可以独立于数据存储节点,实现更好的扩展性。

对比维度 TDSQL Boundless MySQL (基于 InnoDB) 核心差异与影响
加锁对象(对谁加锁) 逻辑键值 (如 Primary Key = 15) 数据的物理存储位置 (Space ID + Page Number + 位图) 根本区别:TDSQL Boundless 不关心数据存储在哪个物理位置,直接对唯一的逻辑标识加锁。MySQL (InnoDB) 的锁与数据的物理页面布局强关联。
单条记录加锁(如:WHERE number=15) 行为一致:无论记录是否存在,都对逻辑键 primary key = 15 加行级锁。 行为分化:1. 记录存在:对 number=15 的记录加行级锁。2. 记录不存在:为防止幻读,会加一个间隙锁,锁定相邻两条记录(如 number=7 和 number=20)构成的区间。 锁的粒度与语义:TDSQL Boundless 的加锁行为更统一、可预测。MySQL (InnoDB) 在记录不存在时会升级为范围更广的间隙锁,可能影响并发插入。
范围查询加锁(如:WHERE row_id BETWEEN 1 AND 20) 整体或自适应分解:1. 无冲突:直接加锁整个逻辑范围 [1, 20]。2. 有冲突:若范围内某点(如 row_id=15)已被其他事务加锁,则会将加锁范围分解为不连续区间, [1, 15) + [15, 20],并等待锁释放。 分段加锁:根据页面的物理存储顺序,将查询范围拆分成多个小的区间(如 (1,3], (3,5], (5,10]…)进行加锁。 加锁策略:TDSQL Boundless 倾向于从逻辑上维护一个大的锁范围,仅在遭遇锁冲突时分解。MySQL (InnoDB) 的加锁粒度受物理数据页的划分影响,更为细碎。
特点总结 直接加锁:加锁过程不依赖物理位置,逻辑清晰,特别适合分布式架构。 加锁前需定位:加锁前必须先确定数据所在的物理页面,锁管理与存储结构耦合紧密。 架构适应性:TDSQL Boundless 的实现在分布式环境下扩展性更好。MySQL (InnoDB) 的实现在单机集中式部署中非常成熟高效。
赞 (0)
上一篇 4天前
下一篇 4天前