tencent cloud

TDSQL Boundless

产品动态
产品简介
产品概述
应用场景
产品架构
实例类型
兼容性说明
使用规范建议
自研内核
内核概述
内核版本更新动态
功能类特性
性能类特性
产品计费
计费概述
购买方式
价格详情
续费说明
欠费说明
退费说明
快速入门
创建实例
连接实例
用户指南
数据迁移
数据同步/订阅
实例管理
参数配置
账号管理
安全组
备份与恢复
数据库审计
标签管理
实践教程
Online DDL 的技术演进与使用实践
锁机制解析与问题排查实践
数据智能调度及相关性能优化实践
TDSQL Boundless 选型指南与实践教程
开发指南
开发指南(MySQL 兼容模式)
开发指南(HBase 兼容模式)
性能调优
性能调优概述
SQL 调优
DDL 调优
性能白皮书
性能概述
TPC-C 测试
Sysbench 测试
API 文档
History
Introduction
API Category
Making API Requests
Instance APIs
Security Group APIs
Task APIs
Backup APIs
Rollback APIs
Parameter APIs
Database APIs
Data Types
Error Codes
通用参考
系统原理
SQL 参考
数据库参数说明
TPC-H 基准测试数据模型参考
错误码信息
安全与合规
常见问题
服务协议
服务等级协议
服务条款
隐私政策
数据处理和安全协议
联系我们
词汇表

悲观事务

PDF
聚焦模式
字号
最后更新时间: 2026-03-06 18:48:25

悲观锁的基本概念

悲观锁是一种数据库并发控制机制,其核心思想是先取锁,再访问。它假设在多用户并发环境下,数据冲突的概率很高,因此在访问数据之前,先对数据加锁,以防止其他事务修改或读取数据,从而确保数据的一致性。
悲观锁的特点是具有强烈的独占性排他性。当事务需要对数据进行操作时,它会先获取锁,确保在事务执行期间,其他事务无法修改这些数据。这种机制适用于数据竞争激烈的场景,能够有效避免脏读、幻读和不可重复读等并发问题。
与乐观锁相比,悲观锁采取了一种更为保守的策略。乐观锁假设冲突很少发生,在提交操作时才检查冲突;而悲观锁则假设冲突经常发生,提前预防冲突。

悲观锁的实现方式

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) 的实现在单机集中式部署中非常成熟高效。



帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈