撤销 Oracle 中的特权会影响使用这些特权的正在进行的事务吗?
Posted
技术标签:
【中文标题】撤销 Oracle 中的特权会影响使用这些特权的正在进行的事务吗?【英文标题】:Does revoking privileges in Oracle affect ongoing transaction that make use of those privileges? 【发布时间】:2011-04-06 11:10:17 【问题描述】:我很好奇这个。如果 DBA(或授予者)撤销用户(被授予者)的权限,而该用户(被授予者)正在进行一个需要这些权限的事务(显然,当用户(被授予者)发出他的事务时,他有这些特权)。
一个简单的场景使这更具体:用户 A 授予用户 B 权限以将数据插入到他(用户 A)模式中的表(比如 Table1)中。用户 B 继续并发出进行大量插入的事务。 在插入过程中,用户 A 撤销了 B 的插入权限。是否:
-
1. 用户 B 的事务中途失败,在 Table1 上执行自动回滚(我假设这是“异常终止”进程的一个示例——conditions for a rollback 之一;是吗?)?如果是,如何处理数据完整性?例如,Oracle 是否保证插入不会在行中间停止?
2.用户B的交易在他的权限被取消之前完成(意味着他不能再进行任何插入)?
从逻辑上讲,我猜应该是 2,但我在 Oracle 文档中找不到任何信息来确认这一点。
谢谢。
编辑:添加一些我编写的 PL/SQL 代码来测试这个(我只是拼凑起来测试这个场景。我不知道 PL/SQL 所以如果我错了,请纠正我)。
/* 首先测试选择权限 */ 设置服务器输出; 声明 v_emp HR.tempemp%rowtype; 开始 dbms_output.enable(300000); for count_var in 1..200000 loop -- 循环很多次,并且在循环退出之前, -- 从授予者的会话中手动撤销权限 选择 * 进入 v_emp 来自 HR.tempemp 其中employee_id = 100; dbms_output.put_line(count_var||' '||v_emp.employee_id); -- 打印 count_var 以便我们知道我们在哪个迭代中 结束循环; 结尾; /* 现在测试插入权限 */ 设置服务器输出; 开始 dbms_output.enable(300000); for count_var in 1..20000000 loop -- 循环很多次,并且在循环退出之前, -- 从授予者的会话中手动撤销权限 插入 HR.tempemp 值(100); dbms_output.put_line(count_var); -- 打印 count_var 以便我们知道我们在哪个迭代中 结束循环; 结尾;观察:
-
1. 撤销一生效,
for
循环就会失效。因此,正如 Dave 所说,每次执行语句时都会检查权限。
2. 对于测试的插入部分,一旦for
循环中途失败,没有 插入(甚至没有 for
经过在受让人的会话中可见)。【问题讨论】:
您谈论交易,但在您对 Erkan 回答的评论中,您的意思听起来像是陈述。 @Dave,你是对的。我应该说“陈述”。 【参考方案1】:我刚刚用以下场景对此进行了测试,结果如下:
1-用户 A 创建表。
2-用户A授权用户B插入。
3-用户 B 插入一行,但没有提交。
4-用户 A 撤销用户 B。
5-用户 B 插入一行,但失败。
5-用户 B 提交成功。
【讨论】:
是的,这个没问题。我想知道 when 撤销生效时插入会发生什么。单个插入将发生得太快而无法实现这种情况。另外,不需要提交的语句怎么办——比如 select 语句:撤销生效时正在处理的 select 语句会在中途终止吗? DDL 语句在整个表上加了一个锁,所以用户 A 的撤销需要等待 INSERT 完成才能在表上加锁。而关于select语句,select语句不会等待任何东西,它只会查看数据库的某个状态——在我们的例子中,这个状态甚至在insert语句之前。 只有一个 select 语句(之前或之后没有 insert 语句)怎么样。我今天编写了一些 PL/SQL 测试代码,其中包含一个长时间运行的for
循环,该循环每次通过循环时都会选择一行(不涉及插入)。我注意到的是,当从授予者的会话 while 发出撤销时,for
正在运行,一旦“看到”撤销,循环就会失败。正如 Dave 在下面所说,每次执行语句时都会检查权限。我会将我的代码添加到 OP,以便您检查它并告诉我是否做错了什么。
实际上,根据我的测试,REVOKE 不会等待 INSERT 完成。我看不出 REVOKE 需要锁定表的任何原因——它实际上并没有以任何方式修改表对象,只是数据字典中的信息。【参考方案2】:
这很容易测试:在模式 A 中创建空表。向模式 B 授予插入权限。在模式 B 中,启动一个长时间运行的 INSERT 语句。在它运行时,撤销插入权限。
如果您这样做,您将看到插入继续运行并成功完成。然后,如果您立即尝试再次执行它,您将得到ORA-01031: insufficient privileges
。所以很明显,Oracle 会为每个语句执行检查一次权限。我浏览了一些文档,没有看到任何直接说明这一点的内容,但这似乎是最合乎逻辑的方法,并且实验支持它。
你问:
“Oracle 是否保证插入不会在一行中间停止?”
如上所示,这与撤销特权的情况无关;但是,如果在处理语句的过程中发生错误,似乎值得更一般地解释 Oracle 的行为。除了 Oracle 中的错误之外,不可能在发生错误时插入并留下部分行。如果在处理单个 SQL 语句的过程中发生任何错误,那么到目前为止由该语句(不是事务)所做的更改将由 Oracle 在内部回滚。例如,如果您要插入许多行并且数据段需要扩展但没有可用空间,则当前语句到目前为止所做的工作将回滚,然后将错误返回到执行该语句的代码.这不是您引用的其他线程中讨论的“异常终止的进程”;进程继续运行并确定如何处理错误——它可以选择回滚整个事务,但它没有义务这样做。
【讨论】:
请问您使用什么代码来进行“长时间运行”插入?我今天刚刚编写了一些 PL/SQL 测试代码,其中包含一个长时间运行的for
循环,每次循环时都会插入一行。当从授予者的会话中发出撤销时,for
循环失败。与您的“实验”不同的是,可以看到 none 的插入(甚至是 for
经历过的插入)。我会将我的代码添加到 OP,以便您检查它并告诉我是否做错了什么。
我一直在重新阅读您的答案,我认为我的代码正是您的意思的一个示例:“如果在处理单个 SQL 语句的过程中发生任何错误,那么更改到目前为止由该语句(不是事务)生成的,由 Oracle 在内部回滚。”是这样吗?现在我更加好奇地看到您长时间运行的插入代码! :)
我正在执行一条语句,基本上是 INSERT INTO empty_table SELECT rownum FROM really_big_table
,它需要 5-10 分钟才能运行(我在插入的列上有一个索引,可能显着减慢了插入速度。)
在您的测试中,语句级别的回滚似乎发生在 PL/SQL 块级别。如果您将这些插入作为独立语句写出并逐个执行,则成功完成的插入不会在以后遇到错误时自动回滚(同样,除非您的 SQLPlus 或其他客户端配置为发生错误时自动回滚事务)。
同意。我认为,这种情况就是 Erkan 所描述的。顺便说一句,“PL/SQL 块级别的回滚语句”是一种特定于实现的行为吗?以上是关于撤销 Oracle 中的特权会影响使用这些特权的正在进行的事务吗?的主要内容,如果未能解决你的问题,请参考以下文章