最近我遇到了一個奇怪的問題,在Oracle數據庫中編程:在可序列化的事務中,我做了一個批量插入(INSERT ... SELECT),之後立即在改變的表格上用SELECT鍵打開遊標。我認爲這個遊標會包含新插入的行,但令我驚訝的是,它的內容不穩定,有時包括所有新插入的行,有時只包含一個子集。Oracle:在可序列化事務中插入後立即選擇
我已經通過在打開遊標之前提交來解決了這個問題,但行爲讓我感到困惑。在同一個事務中插入一個insert後,如果沒有間接提交,實際上可以被信任嗎?或者,這種行爲是否與可序列化的事務相關?我試圖創建一個可重複的測試用例時,只有在添加索引(本例中爲主鍵索引,在實際代碼中爲普通索引)時才能夠獲得此行爲。也許問題在於構建索引所花費的時間,以便SELECT實際上使用不完整的索引來檢索結果?無論如何,這裏有一個可重複的測試用例:
-- Create empty source table
CREATE TABLE TEST_CASE_1 AS
(SELECT 'CONTENT' AS CONTENT
FROM DUAL
WHERE 1 = 2)
-- Add primary key
ALTER TABLE TEST_CASE_1
ADD CONSTRAINT TEST_CASE_1_PK PRIMARY KEY (CONTENT);
-- Create empty destination table
CREATE TABLE TEST_CASE_2 AS
(SELECT 'CONTENT' AS CONTENT
FROM DUAL
WHERE 1 = 2)
-- Example of faulty code
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- Populate with 100.000 rows (I used ALL_OBJECTS but any source of 100.000 rows is good)
INSERT INTO TEST_CASE_1
(SELECT ROWNUM
FROM ALL_OBJECTS
WHERE ROWNUM <= 100000);
INSERT INTO TEST_CASE_2
(SELECT *
FROM TEST_CASE_1
WHERE CONTENT > 0);
COMMIT;
END;
在這個例子中,我希望TEST_CASE_2也有100.000行。重新生成這個測試用例(在一個無負載的數據庫中),我獲得了約400-500行插入。除去將事務設置爲可序列化的語句,我獲得了正確的100.000行計數。
您是否在插入操作時在相同的數據庫會話中打開遊標?你在哪裏做這項工作 - 實際上是在數據庫還是從客戶端應用程序 - 如果後者你有連接池,並且你(有時)爲這兩個操作獲得不同的連接? – 2012-08-06 11:17:16
遊標正在同一會話中打開。最初遊標在數據庫中打開,然後在.NET可執行文件中迭代,但爲了隔離問題,我製作了一個在數據庫中迭代遊標的過程版本,問題依然存在 - 事實上,在執行此操作之前,不要說服自己,問題出現在插入後的選擇中。 – user1578874 2012-08-06 11:37:41
這不應該發生;來自[文檔](http://docs.oracle.com/cd/E11882_01/server.112/e25789/consist.htm#sthref1189)'在序列化隔離級別,事務僅查看在事務時提交的更改 - 不是查詢 - 由交易本身開始並進行更改「,因此您應該看到自己的更改。我猜可能是你的特定版本中的一個錯誤。承諾使得改變隔離級別有點毫無意義。你能發佈一個可重複的測試用例嗎? – 2012-08-06 17:20:04