Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/86.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql Oracle—WITH子句的事务范围_Sql_Oracle_Stored Procedures_Transactions - Fatal编程技术网

Sql Oracle—WITH子句的事务范围

Sql Oracle—WITH子句的事务范围,sql,oracle,stored-procedures,transactions,Sql,Oracle,Stored Procedures,Transactions,考虑以下Java/JUnit集成测试场景 有一个current time DB表,其中存储了当前处理日,集成测试正在更新它以模拟测试时间(我不想讨论这是否是一个好方法)。测试在一个事务中运行,并在最后回滚所有内容 现在,在模拟时间之后,将执行一个查询当前时间表的存储过程,并基于该存储过程执行一些处理 在那里多次查询时间,特别是在WITH子句中,更新的模拟时间不会被读取,而是之前已经存在的旧时间(例如,测试开始前的状态) 在这种情况下,似乎不尊重交易边界。我的理论是,这与Oracle通过查询为构建

考虑以下Java/JUnit集成测试场景

有一个current time DB表,其中存储了当前处理日,集成测试正在更新它以模拟测试时间(我不想讨论这是否是一个好方法)。测试在一个事务中运行,并在最后回滚所有内容

现在,在模拟时间之后,将执行一个查询当前时间表的存储过程,并基于该存储过程执行一些处理

在那里多次查询时间,特别是在WITH子句中,更新的模拟时间不会被读取,而是之前已经存在的旧时间(例如,测试开始前的状态)

在这种情况下,似乎不尊重交易边界。我的理论是,这与Oracle通过查询为构建临时表这一事实有关,但我没有发现任何证据

实际的SQL,带有解释发生了什么的注释:

-- mocking of the test time
-- updates the CURRENT_RUN_DATE to the test time, the previous value was 2016-06-14 08:30:51
UPDATE CURRENT_RUN_DATE SET RUN_DATE = '2014-10-06 07:05:00';

-- SQL of the actual Stored Procedure

WITH SOME_TEMPORARY_VIEW
AS (
  SELECT
    *  
  FROM MY_DATA_TABLE d
  WHERE
-- function F_PREVIOUS_RUN_DATE just select the RUN_DATE from CURRENT_RUN_DATE,
-- yet the old value is read
    d.RUN_DATE = (SELECT F_PREVIOUS_RUN_DATE  FROM DUAL)
)

SELECT
-- here goes some more sql, not important
-- however, if the F_PREVIOUS_RUN_DATE is called here, 
-- it reads the correct RUN_DATE, e.g. the one that was set in the first step
 *
FROM SOME_TEMPORARY_VIEW mv;
使用的Oracle版本:Oracle Database 11g Enterprise Edition 11.2.0.3.0版

更新 根据答案/评论,我将添加更多细节。 在存储过程中,实际使用了两个WITH子句。 依赖项是
实际的\u选择\u语句->另一个\u视图->一些临时的\u视图

实际SQL:

-- mocking of the test time
-- updates the CURRENT_RUN_DATE to the test time, the previous value was 2016-06-14 08:30:51
UPDATE CURRENT_RUN_DATE SET RUN_DATE = '2014-10-06 07:05:00';

-- here begins the problematic SQL
WITH SOME_TEMPORARY_VIEW
AS (
  SELECT
    *,
    (SELECT F_PREVIOUS_RUN_DATE FROM DUAL) as PREVIOUS_RUN_DATE_DEBUG
  FROM MY_DATA_TABLE stic
  WHERE
    -- F_PREVIOUS_RUN_DATE select the PREVIOUS_RUN_DATE from CURRENT_RUN_DATE
    -- the old incosistent value is read here
    stic.RUN_DATE = (SELECT F_PREVIOUS_RUN_DATE FROM DUAL)
),
    ANOTHER_VIEW
  AS (
      SELECT DISTINCT
      -- selects from the first view, does some calculations
        *
      FROM SOME_TEMPORARY_VIEW tv)
SELECT
mv.*,
-- F_PREVIOUS_RUN_DATE reads correct value here
(SELECT F_PREVIOUS_RUN_DATE FROM DUAL) AS PREVIOUS_RUN_DATE_DEBUG2
FROM ANOTHER_VIEW mv;
以下是证明读取了不一致数据的屏幕截图(请参阅调试列):

无论如何,感谢@ibre5041提供有关提示的信息

这是一个有趣的故事


在我应用了
INLINE
提示之后,查询确实按照预期工作。问题似乎与临时表有关,并具体化为临时表。

使用简单的SQL语句,Oracle选择一个时间(或者更准确地说是一个系统更改号或SCN),并且使用的数据在该时间点是一致的

当您在查询中使用存储函数(无论何时)时,该函数将被抛出窗口。优化器可以选择一次或多次执行该函数,并且在该函数中执行的任何查询都作为独立的时间点/SCN运行

你可以使用

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 
使Oracle在整个事务期间使用相同的SCN。

通过简单的SQL语句,Oracle选择一个时间(或者更准确地说是一个系统更改号或SCN),并且使用的数据在该时间点是一致的

当您在查询中使用存储函数(无论何时)时,该函数将被抛出窗口。优化器可以选择一次或多次执行该函数,并且在该函数中执行的任何查询都作为独立的时间点/SCN运行

你可以使用

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 
使Oracle在整个事务期间使用相同的SCN。

如果它像您描述的那样工作,那么它就是一个bug。
WITH
子句可以是内联的,也可以是物化的(请参见
INLINE
MATERIALIZE
提示)。使用这些提示并检查执行计划如何更改。在这两种情况下,查询必须访问读取一致的数据。并且必须返回相同的结果


如果调用pl/sql函数,就会发生这种情况,这些函数也会调用sql。然后,当这些函数在不同的SCN上下文中运行时,它们可以看到幻影(新创建的数据)。正如@Gary所描述的。

如果它像您描述的那样工作,那么它就是一个bug。
WITH
子句可以是内联的,也可以是物化的(请参见
INLINE
MATERIALIZE
提示)。使用这些提示并检查执行计划如何更改。在这两种情况下,查询必须访问读取一致的数据。并且必须返回相同的结果


如果调用pl/sql函数,就会发生这种情况,这些函数也会调用sql。然后,当这些函数在不同的SCN上下文中运行时,它们可以看到幻影(新创建的数据)。正如@Gary所描述的。

事实上,通过
内联
,查询开始正常运行,我在帖子中添加了更多细节。如果提示改变了结果,那么您肯定会面临Oracle错误。我记得不久前我看到过类似的东西。盲目应用最新PSU或联系Oracle支持部门。请参阅@alex的anwser。事实上,通过
内联
,查询开始正常运行,我在帖子中添加了更多详细信息。如果提示改变了结果,那么您肯定会面临Oracle错误。我记得不久前我看到过类似的东西。盲目应用最新PSU或联系Oracle支持。请参阅@alex Thank中的anwser,尝试将隔离级别设置为
SERIALIZABLE
,但结果仍然相同。无论如何,你可能想看看更新后的帖子,我认为整个事情对我来说就像一个bug。谢谢,尝试将隔离级别设置为
SERIALIZABLE
,但结果仍然相同。无论如何,你可能想看看更新后的帖子,我会说整个事情对我来说就像一个bug。