在 COMMIT 之前查看不同 SQL Oracle 会话的更改?

Posted

技术标签:

【中文标题】在 COMMIT 之前查看不同 SQL Oracle 会话的更改?【英文标题】:See changes of a different SQL Oracle session before COMMIT? 【发布时间】:2021-04-06 13:24:24 【问题描述】:

我协调了 Oracle PL/SQL DML 脚本的实施,但在生产环境中,我通常会联系 DBA 团队让他们运行脚本,前提是他们具有适当的权限。

有没有办法让我的用户在实际提交更改之前查看更改?我知道更改将在执行脚本的会话中生效,但是有没有办法让不同的会话,而且,不同的用户可以看到它们?

【问题讨论】:

【参考方案1】:

包DBMS_XA 可以将未提交的事务从一个会话转移到另一个会话。第二个会话可以查看未提交的数据,并可以再次提交、回滚或传递事务。下面的示例基于this oracle-base article,虽然它适用于我,但我之前从未在生产中使用过此功能,并且可能存在我不知道的并发症。

首先,创建示例使用的表:

--DROP TABLE tab1;

CREATE TABLE tab1 (
  id  NUMBER
);

会话 1

将事务超时从 60 秒更改为更大的值:

DECLARE
  l_return  PLS_INTEGER;
BEGIN
  l_return := SYS.DBMS_XA.xa_settimeout(500);
END;
/

开始一个事务,传入一个幻数来命名事务(999):

DECLARE
  l_xid     DBMS_XA_XID := DBMS_XA_XID(999);
  l_return  PLS_INTEGER;
BEGIN
  l_return := SYS.DBMS_XA.xa_start(xid  => l_xid,
                                   flag => DBMS_XA.TMNOFLAGS);
END;
/

在这里做真正的工作,而不是提交:

INSERT INTO tab1 (id) VALUES (1);

结束事务,以便稍后可以附加另一个会话:

DECLARE
  l_xid     DBMS_XA_XID := DBMS_XA_XID(999);
  l_return  PLS_INTEGER;
BEGIN
  l_return := SYS.DBMS_XA.xa_end(xid  => l_xid,
                                 flag => DBMS_XA.TMSUSPEND);
END;
/

数据已从我们的会话中消失 - 此表不包括我们刚刚插入的行。另一个会话需要附加到全局事务并提交或回滚。

select * from tab1;

会话 2

一开始,这个会话看不到数据:

select * from tab1;

使用相同的幻数 (999) 附加到全局事务:

DECLARE
  l_xid     DBMS_XA_XID := DBMS_XA_XID(999);
  l_return  PLS_INTEGER;
BEGIN
  l_return := SYS.DBMS_XA.xa_start(xid  => l_xid,
                                   flag => DBMS_XA.TMRESUME);
END;
/

现在只有这个会话可以看到新行:

select * from tab1;

第二个会话可以提交、回滚或将事务传递给另一个会话。要传递事务,请再次调用 DBMS_XA.XA_END 并进行另一个会话,然后调用 DBMS_XA.XA_START

【讨论】:

只是一个问题:原始会话是否仍然能够提交更改?或者至少他们可以拥有交易?我之所以这样问,是因为 Session-2 的唯一目的是在批准提交之前进行数据分析,但 DBA 组仍然对该过程负责,因此他们需要提交它。 @FelipeVidalOtero 我修改了我的答案,以通过再次调用XA_ENDXA_START 来解释如何多次来回传递事务。 谢谢。我认为这取决于会话的 DML 权限,不是吗?我问是因为我试图运行它:当我使用相同的帐户但不同的选项卡运行它时,它运行正常。但是,使用仅 SELECT 特权用户提供不同的凭据,运行代码“TMRESUME”时,我得到了 ORA-01031(权限不足)。 @FelipeVidalOtero 任何用户都应该能够运行该软件包,它默认授予 PUBLIC。这个查询应该返回EXECUTE 权限:select privilege from all_tab_privs where table_name = 'DBMS_XA' and grantee = 'PUBLIC'; 如果没有返回行,那么 DBA 可能会撤销默认授权,这会破坏很多事情。如果是这种情况,请让他们运行grant execute on sys.dbms_xa to public; 包运行后,您可能还需要您的用户拥有force any transaction 权限才能查看未提交的行。【参考方案2】:

无法在另一个会话中查看一个会话的未提交更改。 但是,由于您正在运行 PL/SQL DML 脚本,您可以尝试在脚本中输入日志以查看脚本进度。 您需要使用带有 AUTONOMOUS 事务的单独 PL/SQL 块来记录数据。

【讨论】:

【参考方案3】:

不,这是不可能的,这是设计使然。根据定义,RDBMS 的 ACID 属性包括“隔离”,它可以防止单个连接相互了解,即看到另一个会话中的变化。

【讨论】:

【参考方案4】:

在提交之前,一个会话无法看到另一个会话所做的更改。

【讨论】:

好的,谢谢。我确实在网络上看到了这一点,以及 UNCOMMITTED 隔离级别的提议(至少我认为我理解这将是假设的方式)。

以上是关于在 COMMIT 之前查看不同 SQL Oracle 会话的更改?的主要内容,如果未能解决你的问题,请参考以下文章

在 SQLAlchemy 中,如何在提交之前预览 SQL 语句以进行调试?

git本地代码回滚

Spring应用程序 - jdbc commit

oracl中的集合操作符

如何查看commit的内容

oracl sql developer使用