【正文】
、建立一個(gè)叫 test1 的存儲(chǔ)過(guò)程,然后執(zhí)行Oracle PL/SQL 開(kāi)發(fā)基礎(chǔ)執(zhí)行后輸入結(jié)果: DML 和異常在一個(gè)程序塊中,如果 DML 語(yǔ)句發(fā)生了異常(這幾乎是 PL/SQL 最常見(jiàn)的異常) ,程序是否回滾這一塊程序中所有 DML 語(yǔ)句,取決于你的異常處理。讓我們來(lái)考慮下面的一個(gè)過(guò)程: CREATE OR REPLACE PROCEDURE empty_library ( pre_empty_count OUT PLS_INTEGER)Oracle PL/SQL 開(kāi)發(fā)基礎(chǔ) IS BEGIN The tabCount function returns the number of rows in the specified table pre_empty_count := tabcount (39。books39。)。 DELETE FROM books。 RAISE NO_DATA_FOUND。 END。注意上面的代碼,我們?cè)趩酒稹癗O_DATA_FOUND”異常前,返回了一個(gè)整數(shù)值表示 books 表中的紀(jì)錄數(shù)?,F(xiàn)在,讓我們使用一段匿名塊來(lái)引用這個(gè)過(guò)程,從而演示一下效果:DECLARE table_count NUMBER := 1。 BEGIN INSERT INTO books VALUES (...)。 empty_library (table_count)。 EXCEPTION WHEN OTHERS THEN (tabcount (39。books39。))。 (table_count)。 END。輸出為:01注意:我們發(fā)現(xiàn)雖然有異常發(fā)生,但是 books 表里面的紀(jì)錄還是被刪除了。Oracle 不會(huì)自動(dòng)地進(jìn)行回滾。但是,奇妙的是,變量 table_count 卻回到了初始值。1. 所以為了避免混亂,我們一般都要自己寫(xiě)回滾塊。下面是要注意的幾Oracle PL/SQL 開(kāi)發(fā)基礎(chǔ)個(gè)事項(xiàng):2. 如果你的程序塊是一個(gè)獨(dú)立自治的事務(wù),那么當(dāng)異常發(fā)生時(shí),你就必須執(zhí)行一個(gè) mit 或 rollback。3. 你可以使用 savepoin 來(lái)控制回滾的范圍。但要注意 savepoint 的設(shè)置范圍。如果異常被傳遞到最外層(比如說(shuō),它跑到“非控制”區(qū)域) ,那么,對(duì)于大部分 PL/SQL 的執(zhí)行環(huán)境(比如 SQL*Plus) ,一個(gè)不可預(yù)見(jiàn)或沒(méi)經(jīng)檢查的回滾將會(huì)自動(dòng)執(zhí)行,造成了一些錯(cuò)誤變更。 DML 和紀(jì)錄從 Oracle 9i Release2 開(kāi)始,你就可以在 insert 和 update 語(yǔ)句中使用紀(jì)錄了。比如下面的代碼例子: CREATE OR REPLACE PROCEDURE set_book_info (book_in IN books%ROWTYPE) IS BEGIN INSERT INTO books VALUES book_in。 EXCEPTION WHEN DUP_VAL_ON_INDEX THEN UPDATE books SET ROW = book_in WHERE isbn = 。 END。這樣帶來(lái)的好處有兩個(gè): 簡(jiǎn)化代碼,用時(shí)髦的話說(shuō),就是把代碼提高到了“記錄層” 。 增加了程序的健壯性,使用“%ROWTYPE” ,當(dāng)表結(jié)構(gòu)發(fā)生變化時(shí),需要維護(hù)的地方就少一些。 基于“記錄” (record )的 INSERT 語(yǔ)句你能夠聲明一個(gè)基于某張表的記錄變量,然后直接把這個(gè)變量的值插入到Oracle PL/SQL 開(kāi)發(fā)基礎(chǔ)表里去。參看以下代碼:需要注意的是,在 INSERT 語(yǔ)句中的 VALUES 子句后面是不能跟“() ”的,如果你按照一般的規(guī)范寫(xiě)了以下的代碼:INSERT INTO dept VALUES(mydept)。那么 Oracle 就會(huì)報(bào)以下錯(cuò)誤:此外,記錄變量的結(jié)構(gòu)必須和表結(jié)構(gòu)完全一致,這也要我們?cè)谑褂脮r(shí)多加小心。 基于“記錄” (record )的 UPDATE 語(yǔ)句With Oracle9i Database Release 2, you can also perform updates of an entire row with a record. The following example inserts a row into the books table with a %ROWTYPE record. Notice that I use a new keyword, ROW, to indicate that I am updating the entire row with a record:同插入語(yǔ)句一樣,你也可以使用記錄變量對(duì)整條記錄進(jìn)行更新。下面的這個(gè)例子就是對(duì) DEPT 表中的一條記錄進(jìn)行更新,其中使用了一個(gè)關(guān)鍵字:ROW,表示對(duì)整一條記錄進(jìn)行更新:Oracle PL/SQL 開(kāi)發(fā)基礎(chǔ)下面有兩點(diǎn)關(guān)于利用記錄變量更新數(shù)據(jù)表的限制: 你必須使用 ROW 語(yǔ)法來(lái)更新整個(gè)記錄,不能僅僅更新某些字段組。 在更新語(yǔ)句中不能使用子查詢。 記錄變量與 RETURNING 子句結(jié)合使用如果 DML 語(yǔ)句影響了一條記錄,你可以把這條記錄的數(shù)值返回給一個(gè)記錄或者組合變量。如下代碼所示:在 RETURNING 子句中,我們還必須把每個(gè)列名寫(xiě)出來(lái),因?yàn)?Oracle 還沒(méi)有支持“*”的寫(xiě)法。 使用記錄變量插入或更新的限制使用記錄變量來(lái)插入或更新,需要注意以下幾點(diǎn):在 SET 子句的左邊,你必須使用 ROW 關(guān)鍵字。而且不能有其他的 SETOracle PL/SQL 開(kāi)發(fā)基礎(chǔ)子句 ,也就是說(shuō),你不能在更新一條記錄的同時(shí)更新一個(gè)單獨(dú)的列。如果你插入一條記錄時(shí),不能只給某個(gè)單獨(dú)列賦值。你不能插入或更新一個(gè)含有內(nèi)嵌記錄的記錄變量。你不能在動(dòng)態(tài) SQL 的 DML 語(yǔ)句中使用記錄變量。因?yàn)檫@需要 Oracle 支持PL/SQL 記錄類(lèi)型和 SQL 語(yǔ)句的綁定,目前只支持 SQL 類(lèi)型的綁定。 事務(wù)管理Oracle 的數(shù)據(jù)庫(kù)管理系統(tǒng)提供了一套非常健壯的事務(wù)管理模型。你的應(yīng)用決定哪一些代碼是一整塊的邏輯單元,需要提交或者回滾。一個(gè)事務(wù)在第一局SQL 語(yǔ)句執(zhí)行就隱式地開(kāi)始了,直到 COMMIT 或 ROLLBACK,或者在ROLLBACK TO SAVEPOINT 之后繼續(xù)。Oracle 提供了以下事務(wù)控制語(yǔ)句:COMMIT提交從上一個(gè) COMMIT 或 ROLLBACK 開(kāi)始的變更,并且釋放所有的鎖。ROLLBACK消除所有從上一個(gè) COMMIT 或 ROLLBACK 開(kāi)始的變更,并且釋放所有的鎖。ROLLBACK TO SAVEPOINT回滾到特定的保存點(diǎn)狀態(tài),并且釋放所有代碼范圍內(nèi)所形成的鎖。SAVEPOINT創(chuàng)建一個(gè)“保存點(diǎn)” ,讓你可以進(jìn)行部分回滾。SET TRANSACTION允許你開(kāi)始一個(gè)只讀或可讀寫(xiě)的會(huì)話,創(chuàng)建一個(gè)隔離層,或者把當(dāng)前會(huì)話分配給一個(gè)特定的回滾段。LOCK TABLE允許你在某種特定方式下所定整張數(shù)據(jù)庫(kù)表。它會(huì)超越普通應(yīng)用于表的行級(jí)別鎖。下面將會(huì)對(duì)以上命令做一個(gè)詳細(xì)的討論。Oracle PL/SQL 開(kāi)發(fā)基礎(chǔ) COMMIT 語(yǔ)句當(dāng)你 COMMIT,你就把你會(huì)話中對(duì)數(shù)據(jù)庫(kù)的更改永久保留了下來(lái)。一旦你提交,你所做的更改就會(huì)對(duì)其他的用戶或會(huì)話可見(jiàn)。COMMIT 語(yǔ)句的語(yǔ)法是:COMMIT [WORK] [COMMENT text]。WORK 關(guān)鍵字是可選的,能夠用來(lái)增加可讀性。COMMENT 關(guān)鍵字確定了一個(gè)與當(dāng)前事務(wù)聯(lián)系的注釋。這個(gè)注釋必須用單引號(hào)括起來(lái),而且長(zhǎng)度不能超過(guò) 50 個(gè)字符。注釋文本一般是由分布式事務(wù)使用,在二相提交框架中,可用來(lái)分析可疑事務(wù)。它與事務(wù) ID 一起存儲(chǔ)在數(shù)據(jù)字典中。注意,COMMIT 釋放你會(huì)話中所有的行級(jí)別和表級(jí)別的鎖,比如一條SELECT FOR UPDATE 語(yǔ)句。它還會(huì)清楚所有從上一個(gè) COMMIT 或ROLLBACK 開(kāi)始設(shè)定的保存點(diǎn)。一旦你 COMMIT 了你的變更,你就不能使用 ROLLBACK 語(yǔ)句回滾它們。下面的語(yǔ)句都是 COMMIT 命令的有效使用: COMMIT。 COMMIT WORK。 COMMIT COMMENT 39。maintaining account balance39。. ROLLBACK 語(yǔ)句當(dāng)你使用了 ROLLBACK 時(shí),你就會(huì)把當(dāng)前會(huì)話事務(wù)中對(duì)數(shù)據(jù)庫(kù)所作的全部或一些變更回退到初始狀態(tài)。為什么你要撤銷(xiāo)變更?從 SQL 的角度看來(lái),ROLLBACK 給你一個(gè)消除錯(cuò)誤的機(jī)會(huì)。比如在下面的語(yǔ)句中:DELETE FROM orders。ROLLBACK 的語(yǔ)法如下:ROLLBACK [WORK] [TO [SAVEPOINT ] savepoint_name]。There are two basic ways to use ROLLBACK: without parameters or with the TO clause to indicate a savepoint at which the ROLLBACK should stop. The parameterless ROLLBACK undoes all outstanding changes in your transaction.Oracle PL/SQL 開(kāi)發(fā)基礎(chǔ)有兩種方式來(lái)使用 ROLLBACK:一種是沒(méi)有參數(shù)的,另一種是含有保存點(diǎn)參數(shù)的。沒(méi)有參數(shù)的 ROLLBACK 會(huì)回滾所有事務(wù)中未完成的改變。而 ROLLBACK TO 會(huì)回退到用戶指定的保存點(diǎn)狀態(tài)。下面是 ROLLBACK 的正確用法: ROLLBACK。 ROLLBACK WORK。 ROLLBACK TO begin_cleanup。注意,當(dāng)你回滾到一個(gè)特定的保存點(diǎn)時(shí),所有在這個(gè)保存點(diǎn)之后的保存點(diǎn)都將被撤銷(xiāo),但是這個(gè)特定的保存就不會(huì)。這意味著你的事務(wù),如果發(fā)生了其他錯(cuò)誤,可以從一個(gè)保存點(diǎn)回滾到相同的保存點(diǎn)。一旦你執(zhí)行了 INSERT、UPDATE 或 DELETE 語(yǔ)句,PL/SQL 就會(huì)自動(dòng)且隱式地生成一個(gè)保存點(diǎn),如果你的 DML 語(yǔ)句發(fā)生錯(cuò)誤,就會(huì)自動(dòng)地回滾到這個(gè)隱式保存點(diǎn)。但是用這種方式,只能回滾最后一條 DML 語(yǔ)句。 SAVEPOINTSAVEPOINT gives a name to, and marks a point in, the processing of your transaction. This marker allows you to ROLLBACK TO that point, erasing any changes and releasing any locks issued after that savepoint, but preserving any changes and locks that occurred before you marked the savepoint.SAVEPOINT 命令可以在你的事務(wù)過(guò)程中創(chuàng)建一個(gè)保存點(diǎn)。這樣就允許你把事務(wù)回滾到這個(gè)點(diǎn)上,從而撤銷(xiāo)所做的修改以及釋放這個(gè)保存點(diǎn)之后的鎖,但是保留了在這個(gè)保存點(diǎn)之前的所有變更和鎖。SAVEPOINT 的語(yǔ)法是SAVEPOINT savepoint_name。在這里“savepoint_name”是一個(gè)不需要聲明的標(biāo)志符,所以保存點(diǎn)的名字必須符合 Oracle 的標(biāo)志符命名標(biāo)準(zhǔn)。要注意的是,savepoint(保存點(diǎn))是不會(huì)被 PL/SQL 程序塊所限制的。如果你在一個(gè)會(huì)話中使用了保存點(diǎn),那么會(huì)話就會(huì)回退到這個(gè)點(diǎn)上,而不會(huì)考慮Oracle PL/SQL 開(kāi)發(fā)基礎(chǔ)這個(gè)保存點(diǎn)是在哪個(gè)過(guò)程、函數(shù)或是匿名塊執(zhí)行的。因此,如果你在一個(gè)遞歸程序中使用了保存點(diǎn),雖然在每一層遞歸中都回生成一個(gè)保存點(diǎn),但是你只能回滾到最近標(biāo)記的那個(gè)保存點(diǎn)上。 數(shù)據(jù)檢索與游標(biāo)關(guān)于 PL/SQL 的特點(diǎn),就在于它緊密地與數(shù)據(jù)庫(kù)結(jié)合在一起,包括改變數(shù)據(jù)庫(kù)內(nèi)的數(shù)據(jù)以及從數(shù)據(jù)庫(kù)中提取信息。本小節(jié)主要探討了 PL/SQL 如何從Oracle 數(shù)據(jù)庫(kù)中查詢數(shù)據(jù),以及如何讓查詢出來(lái)的數(shù)據(jù)可用。當(dāng)你執(zhí)行了一條 PL/SQL 程序中的 SQL 語(yǔ)句時(shí),Oracle RDBMS 就會(huì)分配一塊私有的內(nèi)存區(qū)域給這條語(yǔ)句,并且在系統(tǒng)全局區(qū)(SGA)中管理這條語(yǔ)句所提取的數(shù)據(jù)。這一塊私有內(nèi)存區(qū)含有這條 SQL 語(yǔ)句相關(guān)的信息以及被這條語(yǔ)句影響或檢索的數(shù)據(jù)結(jié)果集。PL/SQL 提供了數(shù)種方式來(lái)操縱上述的私有內(nèi)存區(qū)和其中的數(shù)據(jù),這些方式包含以下:隱式游標(biāo);顯式游標(biāo);游標(biāo)變量;游標(biāo)表達(dá)式;動(dòng)態(tài) SQL。本節(jié)將會(huì)重點(diǎn)闡述隱式游標(biāo)、顯式游標(biāo)以及與游標(biāo)相關(guān)的一些特性。 游標(biāo)的基礎(chǔ)概念簡(jiǎn)單來(lái)說(shuō),你可以把游標(biāo)看成是指向數(shù)據(jù)表的一種指針,如下面的這個(gè)游標(biāo)就與 EMP 表的全部列關(guān)聯(lián)在一起:CURSOR emp_cur IS SELECT * FROM EMP。一旦申明了這樣一個(gè)游標(biāo),你就可以打開(kāi)它,如下:OPEN emp_cur。然后還可以從中取出記錄:FETCH emp_cur INTO emp_re