← 返回首页

我在 Oracle 权限里踩过的那些坑

编程开发 亲身经历 公开
内容简要
在Oracle数据库中,由于权限和角色设置不当,导致无法创建存储过程、访问错误表、存储过程内部提交数据等问题。
坑点
权限和角色设置不当,导致无法创建存储过程、访问错误表、存储过程内部提交数据等问题。
注意事项

1. 确保拥有足够的权限来创建存储过程。

  • 检查是否有足够的表权限和代码权限。
  • 确保直接授予用户权限而非通过角色。

2. 明确指定表名,避免访问错误表。

  • 在所有SQL语句中明确指定schema。
  • 避免使用默认表名。

3. 注意存储过程中的提交和回滚操作。

  • 检查存储过程中是否有COMMIT语句。
  • 根据需要使用ROLLBACK或手动清理测试数据。

4. 谨慎使用同义词和公共同义词。

  • 避免使用同义词导致访问错误表。
  • 避免使用公共同义词导致权限问题。

一、我以为我是“半个小 DB”

刚接手项目时,我挺自信。我能 SELECT、INSERT、UPDATE、DELETE 业务表,还能建表、改表结构,就觉得差不多是“半个 DBA”了。

直到我写了人生中第一个存储过程,兴冲冲地执行:

CREATE OR REPLACE PROCEDURE p_test IS
BEGIN
  NULL;
END;
/

Oracle 冷冷地回了一句:

ORA-01031: insufficient privileges

我愣住了:我能改表数据,居然连一个“什么也不干”的过程都建不了?

后来才明白,表权限和代码权限是两套东西。我能对表做增删改查,但 CREATE PROCEDURE 是另一回事。我联系 DBA,他只回了一句:

“正式表都在 OADBA 下,你别乱建过程。”

那一刻,我觉得自己像个被没收了工具的装修工。


二、我在自己账号下测试,结果改错了表

DBA 不让我在 OADBA 下建过程,我就在自己的账号 A 下建。表里写的是:

SELECT * FROM yy010;

我想当然地觉得,既然我一直操作 OADBA.YY010,Oracle 总该知道我要访问哪张表吧?

结果一测试,程序跑得飞快,没报错。我赶紧去查数据,却越查越心凉:改的不是 OADBA.YY010,而是我自己账号下的 A.YY010。

我这才发现,Oracle 根本不会“猜”你想访问哪个 schema。它只看当前用户。我写的 yy010,默认就是 A.YY010。

那天晚上我把所有表名都改成了 OADBA.YY010。虽然多打了几个字,但至少不再改错表了。


三、匿名块能跑,塞进存储过程就“表不存在”

解决了表名问题,我又遇到一个诡异的现象。

这段代码,我直接执行,一点问题没有:

DECLARE
  v_cnt NUMBER;
BEGIN
  SELECT COUNT(*) INTO v_cnt FROM oadba.yy010;
END;
/

可一旦塞进存储过程,编译就报:

PL/SQL: ORA-00942: table or view does not exist

我反复确认:oadba.yy010 就在那里,我能查,我能改,它怎么就“不存在”了?

查了很久才知道,原来我的表权限是通过一个角色拿到的。匿名块认角色,但存储过程不认。PL/SQL 编译时,只认直接授予我的权限。

我厚着脸皮找 DBA:

“能不能把权限直接授给我,别走角色?”

DBA 看了看我,叹了口气:

GRANT SELECT, INSERT, UPDATE, DELETE ON oadba.yy010 TO A;

终于,存储过程编译通过了。那种感觉,就像终于拿到了一张写着自己名字的门票。


四、有人让我建同义词,我差点又踩坑

权限问题解决后,有个同事看我每次都写 OADBA.,忍不住说:

“你建个同义词啊,省得每次都写 schema。”

我想也没想,差点就执行:

CREATE SYNONYM yy010 FOR oadba.yy010;

还好我停了一下,先查了查自己账号下有没有 YY010 表:

SELECT * FROM user_objects WHERE object_name = 'YY010';

这一查,冷汗都出来了。我自己账号下还真有一张 YY010 测试表。

如果我建了同义词,Oracle 还是会先找我自己的表,同义词照样被遮蔽。yy010 这个名字,在我的环境里始终是指向 A.YY010。

后来我明白了:同义词只是别名,不是复制表,也不能帮我自动选对表。

从那以后,我的正式代码里永远写着:

SELECT * FROM oadba.yy010;

我宁可多敲几个字母,也不想再猜 Oracle 到底把我指向了哪里。


五、我亲手删掉了自己插入的测试数据

有一次测试一个写数据的存储过程,我特意选了一条测试数据,跑完检查也没问题,然后放心地下班了。

第二天,有个同事在群里问:

“谁昨天往 OADBA.YY010 里插了一条奇怪的数据?”

我一看,正是我昨晚测试的那条。我赶紧解释:

“我测试完执行 ROLLBACK 了啊!”

同事回了一句:

“你那个存储过程里不是写了 COMMIT 吗?”

那一刻我恨不得把键盘吃了。原来,过程内部的 COMMIT 已经把数据提交了,我在外面 ROLLBACK,什么也撤不回来。

从那以后,我测试任何带写操作的过程,都会先看一眼里面有没有 COMMIT,再决定是用 ROLLBACK 回滚,还是用专门的测试数据、测完手动清理。


六、别再让我建公共同义词了

还有一次,A 要访问 B 的表,有人提议:

“让 B 建个公共同义词吧,大家都方便。”

我当时就说:“别。”

不是我固执,而是我已经见过太多“悄悄访问错表”的事故了。只要某个用户自己下也有一张同名表,公共同义词就会被遮住。看起来大家都在访问 yy010,实际上可能各自访问的是不同 schema 下的表。

最后我们用了最朴素的方案:

  1. B 给 A 授权:

CODE9

  1. A 老老实实写:

CODE10

没有同义词,没有歧义,谁看代码都知道访问的是哪张表。


我最终学到的几件事

  1. 表权限不等于代码权限​

我能改表,不代表我能建存储过程。

  1. yy010 不等于 OADBA.YY010​

当前用户是谁,yy010 默认就指向谁。

  1. 存储过程不认角色权限​

权限必须直接授予我的用户。

  1. 同义词只是别名,不是保险箱​

它不复制数据,也不能代替授权。

  1. 公共同义词是全局的,也是最危险的​

一个同名表,就可能把你的 SQL 悄悄拐到别处。

  1. 先看清过程里有没有 COMMIT 再测试​

不然,你的测试数据可能就永远留下了。

如果你也常在 Oracle 里写存储过程,我只送你一句话:

别猜 Oracle 会访问哪张表,写清楚 schema.表名,让所有人都看得懂。​ 我踩过的坑,希望你不用再踩一遍。
本文内容仅代表作者个人观点、经历或转述,不代表任何官方立场,仅供参考,不构成任何专业建议。据此操作产生的风险由读者自行承担。
发布于 2026-10-30 08:50:30 ID: 31