【发布时间】:2016-07-19 18:47:48
【问题描述】:
考虑以下 Java/JUnit 集成测试场景。
有一个 当前时间 数据库表,其中存储了当前处理日期,集成测试正在更新它以模拟测试时间(我不想讨论这是否是一个好方法)。测试在事务中运行,最后一切都回滚。
现在,在模拟时间之后,会执行一个查询当前时间表的存储过程,并在此基础上进行一些处理。
时间在那里被多次查询,但特别是在 WITH 子句中,更新的模拟时间不会被读取,而是之前已经存在的旧时间(例如测试前的状态开始)。
在这种情况下,似乎没有遵守事务边界。我的理论是这与 Oracle 为 WITH 查询构造临时表这一事实有关,但我没有找到任何证据。
用 cmets 解释发生了什么的实际 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 Release 11.2.0.3.0
更新
根据答案/cmets,我正在添加更多详细信息。
在存储过程中,实际使用了两个 WITH 子句。
依赖是ACTUAL_SELECT_STATEMENT -> ANOTHER_VIEW -> SOME_TEMPORARY_VIEW
实际的 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;
这是证明读取了不一致数据的屏幕截图(请参阅 DEBUG 列):
无论如何,感谢 @ibre5041 提供有关提示的信息。
下面是有趣的故事。
应用INLINE 提示后,查询确实工作如预期。看起来问题与 WITH 和物化到临时表有关。
【问题讨论】:
标签: sql oracle stored-procedures transactions