ROWID是Oracle中每行数据的唯一物理地址,不可插入或更新,仅能用作WHERE条件实现高速单行定位;它不稳定,易因表维护操作而变化,不可长期缓存或替代主键。

ROWID 是 Oracle 的物理地址,不是普通字段
Oracle 的 ROWID 是每行数据在数据库中的唯一物理地址,它不参与表定义,也不出现在 DESC table_name 结果里,但可通过 SELECT ROWID, ... FROM table_name 查到。它不能被插入或更新,但能用作 WHERE 条件实现精准、高速的单行定位——这是它最核心的用途。
常见误区是试图把它当普通列写进 UPDATE 语句的 SET 子句,比如 SET ROWID = 'AAABBB...' ,这会直接报错 ORA-01747: invalid user.table.column, table.column, or column specification。
用 ROWID 做 WHERE 条件更新,比主键还快
当你要更新某一行,且已经持有它的 ROWID(比如从上一步查询中获取),直接用它做条件即可。相比基于主键或业务字段的更新,它跳过索引查找和数据块定位的中间步骤,直击物理位置。
Java 中典型写法:
立即学习“Java免费学习笔记(深入)”;
String sql = "UPDATE employees SET salary = ? WHERE ROWID = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setBigDecimal(1, new BigDecimal("8500"));
ps.setString(2, "AAAFd4AAFAAAANgAAA"); // 这是上一步查到的 ROWID 字符串
ps.executeUpdate();
}
-
ROWID在 JDBC 中按字符串处理,用setString()即可,无需特殊类型 - 确保传入的
ROWID未被截断或编码损坏(长度通常为 18 字符,含大小写字母和数字) - 注意事务隔离:如果该行已被其他事务修改并提交,
ROWID仍有效,但更新的是新版本;若该行被删除,UPDATE影响行为 0,不会报错
ROWID 不稳定,不能长期缓存
ROWID 不是永久标识符。以下操作会导致它变化:
- 表启用行迁移(
ALTER TABLE ... ENABLE ROW MOVEMENT)后发生UPDATE导致行移动 - 执行
ALTER TABLE ... SHRINK SPACE或在线重定义(DBMS_REDEFINITION) - 分区表中行跨分区移动(如更新分区键)
- 导出导入(EXP/IMP 或 Data Pump)后重建表
所以不要把 ROWID 存进业务系统当“主键替代品”,也不要在缓存中长期保留。它只适合“查—改”紧耦合的短生命周期场景,比如 Web 表单编辑:先 SELECT ROWID, name, salary FROM emp WHERE id = ?,用户改完后带 ROWID 回来更新。
用 SELECT FOR UPDATE + ROWID 避免并发覆盖
如果更新逻辑涉及“读取→计算→写入”,且需防止其他线程同时修改同一行,光靠 ROWID 不够。必须配合行级锁:
SELECT ROWID, salary FROM employees WHERE id = 123 FOR UPDATE
这样在 Java 中拿到 ROWID 后再执行 UPDATE ... WHERE ROWID = ?,就能保证从读到写之间该行被锁定。否则可能出现 A 读、B 读、A 写、B 写的覆盖问题。
注意:FOR UPDATE 会阻塞其他对同一行的 FOR UPDATE 或 DML,但不会阻塞普通 SELECT(除非加了 FOR UPDATE NOWAIT 等选项)。
真正难的是判断什么时候该用 ROWID 而不是主键:它快,但脆弱;它精准,但无业务意义。一旦表结构或维护策略变动,依赖 ROWID 的代码就可能静默失效——这点比任何语法细节都值得多看两眼。


















