SELECT FOR UPDATE SKIP LOCKED --- 一个未公开但十分有用的特性

本文详细介绍了Oracle中未公开的SELECT FOR UPDATESKIPLOCKED特性,通过实例演示了如何使用NOWAIT和SKIPLOCKED选项在并发场景下高效地处理数据。特别关注其在消息队列操作中的应用,提供了实际案例分析,帮助理解如何避免阻塞并实现高效的数据处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SELECT FOR UPDATE SKIP LOCKED 选项是ORACLE的一个未公开的特性,它的含义是SELECT时跳过被锁的记录。

考虑下面的例子:

会话1

SQL> select * from sex_dict ;

 

 SERIAL_NO S SEX_ INPUT_CO

---------- - ---- --------

         1 1     N

         9 0 未知  WZ

         2 2     N

         4 9 未定  WD

SQL> select * from sex_dict  where serial_no = 1 for update ;

 

 SERIAL_NO S SEX_ INPUT_CO

---------- - ---- --------

         1 1     N

 

会话2

查询并锁住serial_no in (1,2) 的记录

SQL> select * from sex_dict where serial_no in ( 1, 2) for update ;

 

此时会话2挂住,直到会话1事务结束。

 

加上”NOWAIT”选项

SQL>  select * from sex_dict where serial_no in ( 1, 2) for update nowait ;

 select * from sex_dict where serial_no in ( 1, 2) for update nowait

               *

ERROR at line 1:

ORA-00054: resource busy and acquire with NOWAIT specified

因为serial_no = 1的记录被会话锁住,所以这个操作没有成功。

 

加上SKIP LOCKED选项

SQL>  select * from sex_dict where serial_no in ( 1, 2) for update nowait  skip locked;

 

 SERIAL_NO S SEX_ INPUT_CO

---------- - ---- --------

         2 2     N

 

会话2只锁住serial_no=2的记录,跳过serial_no=1的记录。

 

这个特性适合例如消息队列的操作,当消息到达时,处理消息的各个客户选取并锁住一个消息处理,但不能阻塞其它客户处理消息。其它客户则处理没有被锁的消息。这个可以参考AnySQL.net的《Oracle中如何跳过被别人锁住的记录?

利用这个特点,Tomac给出了一个不跳号序列号的方法

<think>嗯,用户的问题是关于在DBeaver中正确使用SELECT FOR UPDATE语句并粘贴数据。用户可能遇到了事务锁定或数据更新失败的情况,需要明确的操作指引。 从引用内容来看,用户之前接触过DBeaver生成SQL语句(引用1)和基础查询操作(引用2),但对事务控制的理解可能受Oracle经验影响(引用3提到Oracle默认手动提交而PostgreSQL自动提交)。用户真正需要的是解决两个核心问题:如何通过SELECT FOR UPDATE锁定行,以及如何在锁定后安全修改数据。 需要特别注意事务边界的处理,因为引用3强调过不同数据库的autocommit差异很大。用户可能没意识到DBeaver默认自动提交,这会导致SELECT FOR UPDATE的锁立即释放。应该分步骤说明: 1. 必须手动开启事务(关闭autocommit) 2. 执行SELECT ... FOR UPDATE锁定目标行 3. 在结果集直接编辑数据 4. 显式提交事务 引用4提到的"粘贴数据"操作其实有误导性,PL/SQL Developer的右键粘贴模式在DBeaver并不适用。应该强调DBeaver特有的"直接编辑结果集"功能,这才是最高效的方式。 对于粘贴场景,需区分两种情况: - 少量数据:在锁定后的结果集里逐行修改更安全 - 大批量更新:建议生成UPDATE语句执行,避免长时间锁表 最后要提醒Oracle迁移用户的常见陷阱(引用3),比如PostgreSQL执行DML后不提交不会持久化,但锁的行为也可能不同。相关问题的设计可以延伸到事务隔离级别和锁机制的深入讨论。</think>在 DBeaver 中使用 `SELECT FOR UPDATE` 语句并正确粘贴/修改数据,需要遵循特定的事务流程以确保行锁生效和数据一致性。以下是详细步骤: ### 📌 正确使用 SELECT FOR UPDATE 及修改数据步骤 1. **🔧 关闭自动提交(关键步骤)** - 顶部菜单栏 → **窗口** → **首选项** → **连接** → **事务隔离** - 取消勾选 **"自动提交"**(默认为开启状态)[^3] - *若不关闭,查询后锁会立即释放,导致数据冲突* ✅ 2. **🔒 执行锁定查询** 在 SQL 编辑器中输入并执行(以 `student` 表为例): ```sql START TRANSACTION; -- 显式开启事务(部分数据库可省略) SELECT * FROM student WHERE id = 100 FOR UPDATE; -- 锁定目标行 ``` - ⚠️ 执行后目标行被独占锁定,其他会话的修改会被阻塞 3. **📝 修改数据(两种方式)** **方式一:直接编辑结果集(推荐)** - 在查询结果的 **数据网格** 中双击需要修改的单元格 - 输入新值 → 按 `Enter` 保存(此时数据暂存于本地) - *注意:编辑后需提交事务才会持久化* [^4] **方式二:生成 UPDATE 语句** - 右键表名 → **生成 SQL** → **UPDATE** - 修改生成的语句并执行(需在同一个事务连接中): ```sql UPDATE student SET name = '新值' WHERE id = 100; ``` 4. **💾 提交事务释放锁** - 点击工具栏 **提交** 图标(✔️)或执行: ```sql COMMIT; -- 提交修改并释放行锁 ``` - 若放弃修改则点 **回滚** 图标(↩️) --- ### ⚠️ 关键注意事项 1. **事务一致性** - 所有操作必须在 **同一连接会话** 中完成,否则锁失效 - PostgreSQL/Oracle 等需显式提交,MySQL 默认自动提交需关闭[^3] 2. **锁超时问题** - 长时间未提交会导致锁等待超时(如 MySQL 默认 `innodb_lock_wait_timeout=50s`) - 复杂操作建议提前规划事务范围 3. **结果集编辑限制** - 部分驱动(如 Oracle JDBC)可能不支持直接网格编辑 - 此时需用 **方式二** 手动执行 UPDATE --- ### 🔍 相关问题 1. 如何在 DBeaver 中监控当前数据库的锁状态? 2. `SELECT FOR UPDATE NOWAIT` 和 `SKIP LOCKED` 子句的使用场景有何区别? 3. 事务隔离级别(如 Read Committed vs Repeatable Read)对行锁行为有何影响? 4. DBeaver 连接不同数据库(MySQL/PostgreSQL/Oracle)时,事务配置有哪些关键差异?[^3] > 引用说明: > [^3]: 不同数据库的自动提交机制差异是事务操作的核心,关闭自动提交是保证行锁有效的关键前提。 > [^4]: DBeaver 的结果集直接编辑功能依赖 JDBC 驱动支持,若遇限制需改用显式 SQL 更新。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值