PL/SQL是Oracle在標準SQL語言上的過程性擴展,它允許嵌入SQL語句、定義變量和常量、使用過程語言結構(條件分支語句和循環語句)、使用異常來處理Oracle錯誤等。在任何運行Oracler的平臺上,應用開發人員都可以使用PL/SQL。通過使用PL/SQL,可以在一個PL/SQL塊中包含多條SQL語句和PL/SQL語句。PL/SQL可以用于創建存儲過程、觸發器和程序包等,也可以用于處理業務規則、數據庫事件或為SQL命令的執行添加程序邏輯。
PL/SQL是一種可移植的高性能事務處理程序,它支持SQL和面向對象編程,提供了良好的性能和高效的處理能力,具有以下6個方面的優點。
1.提高應用程序的運行性能
在編寫OracoeOracle數據庫應用程序時,開發人員可以直接將PL/SQL塊內嵌到應用程序中,其最大的優點是可以降低網絡開銷、提高應用程序性能。對于其他異構數據庫(例如SQL Server、Sybase、DB2等),當應用程序訪問RDBMS時,每次只能發送單條SQL語句。而對于Oracle數據庫而言,通過使用PL/SQL塊,可以將多條SQL語句組織到同一個PL/SQL塊中,從而降低網絡開銷,提高應用程序的性能。
2.提供模塊化的程序設計功能
當開發數據庫應用程序時,為了簡化客戶端應用程序的開發和維護工作,可以首先將企業規則或商業邏輯集成到PL/SQL子程序(過程、函數和包)中,然后在應用程序中調用子程序實現相應的程序功能。
3.允許定義標識符
當使用PL/SQL開發應用模塊時,為了使應用模塊與應用環境實現數據交互,需要定義變量、常量、游標等各種標識符。例如,函數get_sal中的no為輸入參數,用于接收雇員編號的輸入值,而salary變量則用于臨時存儲雇員工資。
4.具有過程語言控制結構
PL/SQL是Oracle在標準SQL上的過程性擴展,它不僅允許在PL/SQL塊中嵌入SQL語句,而且允許在PL/SQL塊中使用各種類型的條件分支語句和循環語句。
5.具有良好的兼容性
PL/SQL是Oracle提供的用于實現應用模塊的語言,在允許運行Oracle的任何平臺上都可以使用PL/SQL。例如,在Oracle數據庫中使用PL/SQL開發數據庫端的過程、函數和觸發器,以及在Oracle提供的應用開發工具Developer中使用PL/SQL開發客戶端的過程、函數和觸發器。
6.處理運行錯誤
當設計并開發應用程序時,為了提高應用程序的健壯性,可以使用PL/SQL提供的異常處理(EXCEPTION)集中處理各種Oracle錯誤和PL/SQL錯誤,從而簡化錯誤處理。
所有的PL/SQL程序都以塊作為基本單位組成。塊中包含過程化語句和SQL的DML語句。這些塊可以按順序出現,也可以相互嵌套(一個塊在別一個塊的內部)。按是否帶有名稱以及在數據庫中的存儲方式,塊可以分為以下5種。
1.匿名塊
匿名塊是出現在應用程序中的沒有名稱且不存儲到數據庫中的塊。匿名塊可以出現在SQL語句出現的地方,它們可以調用其他程序,卻不能被其他程序調用。
2.命名塊
命名塊是一種帶有標簽的匿名塊,標簽為塊指定了一個名稱。
3.子程序
子程序是存儲在數據庫中的過程(PRocedure)、函數(function),生成之后可以被多次執行。
4.程序包
程序包是存儲在數據庫中的一組子程序、變量定義。程序包中的子程序可以被其他程序包或者子程序調用。如果聲明為局部子程序,則只能在定義該局部子程序的塊中被調用該局部子程序。
5.觸發器
觸發器是一種存儲在數據庫中的命名塊,生成之后可以被多次執行。在相應的觸發器事件發生之前或之后就會被執行一次或多次(每行記錄一次)。觸發器事件一般是指對特定的數據庫表、視圖進行的操作,如INSERT、UPDATE和DELETE等(被稱為DML觸發器);或者對數據庫級的操作,如關閉、啟動、登錄、退出數據庫,創建對象、修改對象、刪除對象等(稱為系統觸發器)。
PL/SQL程序塊由3個部分組成:定義部分、執行部分和異常處理部分。其中,定義部分用于定義常量、變量、游標、異常和復雜數據類型等;執行部分用于實現應用模塊功能,該部分包含需要執行的PL/SQL語句和SQL語句;異常處理部分用于處理執行部分可能出現的運行錯誤。PL/SQL塊的基本結構如下:
DECLARE
定義部分
BEGIN
執行部分
EXCEPTION
異常處理部分
END;
其中,定義部分以DECLARE開始,該部分是可選的;執行部分以BEGIN開始,該部分是必須的;異常處理部分以EXCEPTION開始,該部分是可選的;END則是PL/SQL程序塊的結束標記。以下示例創建匿名程序塊,用于接收用戶輸入的員工編號,輸出該員工的姓名,以及處理用戶輸入的員工編號不存在的異常
注意
DECLAREE、BEGIN和EXCEPTION后面沒有“;”(分號),而END后則必須要帶“;”(分號)。
在PL/SQL程序中加入注釋可以幫助理解程序,PL/SQL編譯器在編譯時會忽略注釋,PL/SQL的注釋分為單行注釋和多行注釋。
1.單行注釋
單行注釋可以放在一行的任何地方,由兩條短橫線(--)開始。
2.多行注釋
多行注釋“/*”開始、“*/”結束,可以跨越多行,但不允許嵌套。
在調試PL/SQL程序時,完全可以使用單行或多行注釋來將暫時不需要或不正確的語句進行注釋或禁用。
在聲明部分中可以聲明需要使用的常量、變量、函數、游標、異常處理名稱等。
1.聲明
聲明常量、變量的語法如下:
語法:
Iidentifier_name [CONSTANT] data_type [NOTNULL][:=value_expression]|[DEFAULT value_expression]
其中,identifier_name指定需要聲明的常量、變量的名稱;data_type指定數據類型;“:=”是賦值運算符(或使用DEFAULT);value_expression是賦值表達式。如果語句中有CONSTANT,則表明聲明的是一個常量;如果有NOT NULL,則表明聲明的變量是不能為空(即在聲明時必須賦值)。聲明常量時應該立即賦值,如果沒有賦值則表示初始化為NULL。
注意:
在PL/SQL中,每一行中能聲明一個常量或變量。在引用一個常量或變量之前,必須先對其進行聲明。
2.使用SELECT INTO語句為變量賦值
除了可以使用常量為變量賦值之外,還可以將從數據庫表中查詢獲得的值賦給變量。通過SELECT INTO語句可以從數據庫表中查詢的結果賦予變量,根據雇員編號獲得雇員工資、補助和總工資,代碼如圖4.1.1所示。該示例代碼中,從數據庫中根據員工編號查詢員工姓名,并把員工姓名賦給變量v_ename。
編寫PL/SQL程序時,若臨時存儲數值,則必須定義變量和常量;若在應用環境和子程序之間傳遞數據,則必須為子程序指定參數。而在PL/SQL程序中定義變量、常量和參數時,必須為它們指定PL/SQL數據類型。常見的數據類型如表14-1-1所示。
表14-1-1 部分數據類型及說明
數據類型 | 說明 |
char | 表示固定長度字符串,長度不夠時使用空格來補充,最多可以存儲2000字節。 |
varchar2 | 表示可變長字符串,最多可以存儲4000字節。 |
number | 可以存儲正數、負數、零、定點數和精度為38的浮點數。其格式為:number(m,n),其中m表示精度代表數字的總位數;n表示小數點右邊數字的位數。 |
date | 用于存儲表中的日期和時間數據,取值范圍是公元前4712年1月1日到公元9999年12月31日。Date類型的長度是7,7個字節分別表示世紀、年、月、日、時、分和秒。 |
timestamp | 用戶存儲日期的年、月、日、小時、分和秒值。其中,秒值精確到小數點后6位數,該數據類型同時包含時區信息。 |
clob | 用于存儲可變長度的字符數據,最多可存儲4GB。該數據類型用于存儲varchar2類型不能存儲的長文本信息。 |
blob | 用于存儲較大的二進制對象,如圖形、視頻剪輯和聲音剪輯等,該類型最多可存儲4GB數據。 |
PL/SQL中的數據類型除了表1-1-1所列出的以外還有以下常用的類型:
1.%TYPE
當定義PL/SQL變量存放值時,必須確保變量使用合適的數據類型和長度,否則可能在運行過程中出現PL/SQL運行錯誤。此時,可以使用%TYPE屬性來定義變量。當使用%TYPE屬性定義變量時,Oracle會自動地按照數據庫列或其他變量來確定新變量的類型和長度。圖4.1.3演示了使用%TYPE定義變量的過程。
2.%ROWTYPE
如果一張表中包含較多的列,則可以使用%ROWTYPE來定義一個表示表中一行記錄的變量,這樣比分別使用%TYPE來定義表示表中各個列的變量理更加簡潔。為了使一個變量的數據類型與一張表中記錄的各個列的數據類型對應一致,Oracle提供了%ROWTYPE定義定議方式。
在圖4.1.3中,根據輸入的員工編號查詢該員工姓名、部門編號,并將查詢結果存儲在變量v_ename、v_deptno中。然后根據根據部門編號查詢一條部門信息并將該信息存入變量v_dept_row中。
3.RECORD
PL/SQL記錄類似于高級語言中的結構,每個PL/SQL記錄一般都包含多個成員。當使用PL/SQL記錄時,首先需要在定義部分定義記錄類型和記錄變量,然后在執行部分引用該記錄變量。當引用記錄成員時,必須將記錄變量作為前綴,格式為“記錄變量.記錄成員”。
語法:
Type record_name is record
(
V1 data_type1 [not null] [:=default_value],
V2 data_type2 [not null] [:=default_value],
Vndata_typen [not null] [:=default_value]
);
4.TABLE
索引表相當于一個鍵值集合,鍵是唯一的,用于查找對應的值。鍵可以是整數或字符串。
語法:
Type table_name is table of element_type [not null]
index by [binary_integer | pls_integer |varchar2]
關鍵字INDEX BY表示創建一個主鍵索引,以便引用記錄表變量中的特定行。
流程控制是PL/SQL對SQL最重要的擴展,流程控制結構包括條件控制、循環控制和順序控制。
在許多情況中,需要按照某種條件來選擇執行某些語句段。條件控制先測試一個條件,然后根據測試的結果選擇、運行不同的語句段。條件結構中允許嵌套。
1.IF…THEN…END IF結構
最簡單的條件控制結構。
語法:
If IF 條件表達式 THEN
語句段
END IF;
2.IF…THEN…ELSE…END IF結構
二重條件分支結構。如果滿足條件則執行一組操作,不滿足條件則執行另外一級組操作。
語法:
IF 條件表達式 THEN
語句段1
ELSE
語句段2
END IF;
3.IF…THEN…ELSIF…END IF結構
多重條件分支結構。如果滿足第一個條件,則執行第一種操作;如果不滿足第一個條件,則檢查是否滿足第二個條件,如果滿足則執行第二種操作;如果不滿足第二個條件,則檢查是否滿足第三個條件……依此類推。
語法:
IF 表達式1 THEN
語句段1
ELSIF 條件表達式2 THEN
語句段2
……
ELSIF 條件表達式n THEN
語句段n
ELSE
語句段
END IF ;
CASE結構
CASE結構是在Oracle 9i中引的另一種邏輯判斷結構,它提供了另一種邏輯判斷的實現方法。
語法:
CASE 表達式
WHEN 條件表達式結果1 THEN
語句段1;
WHEN 條件表達式結果2 THEN
語句段2;
…...
ELSE
語句段n;
END CASE;
CASE結構的另一種語法格式被稱為CASE搜索結構,語法如下:
語法:
CASE
WHEN 條件表達式結果1 THEN
語句段1;
WHEN 條件表達式結果2 THEN
語句段2;
……
ELSE
語句段n;
END CASE;
其中,CASE結構非常適用于從多個值中選擇一個,以決定需要執行的語句段。在實際應用中,CASE結構的可讀性及有效性更高,盡量將很長的IF…THEN…ELSIF…END IF語句改寫成CASE結構。
為了在編寫的PL/SQL塊中重復執行一條語句或者一組語句,可以使用循環控制結構。編寫循環控制結構時,用戶可以使用基本循環、WHILE循環和FOR循環等類型的循環語句。
1.基本循環
在PL/SQL中,格式最簡單的循環語句是基本循環語句,它以LOOP開始,以END LOOP結束。
語法:
LOOP
語句段;
EXIT [WHEN 條件表達式]
END LOOP;
上述語法中,當使用基本循環時,無論是否滿足條件,語句至少會被執行一次。當條件表達式為TRUE時,會退出循環,并執行END LOOP后的操作。
注意:
EXIT語句必須放在循環體內,且只能退出循環體,不能退出PL/SQL塊。當需要退出PL/SQL塊時,應該使用RETURN語句。
WHILE循環
基本循環至少需要執行一次循環體內的語句,而WHILE循環中,只有當條件為TRUE時,才會執行循環體內的語句。我們改造圖4.1.9的示例,使用while循環來實現
FOR循環
當使用基本循環或WHILE循環時,需要定義循環控制變量。循環控制變量不僅可以使用NUMABENUMBER類型,還可以使用其他數據類型。當使用FOR循環時,Oracle會隱含定義循環變量。
默認情況下,當使用FOR循環時,每次循環,時控制變量會自動增加1;如果指定了REVERSE選項,則每次循環時循環控制變量會自動減少1。在循環體內部可以引用循環變量,但不能對其賦值。
PL/SQL異常是指通過編譯的PL/SQL程序在運行時產生的錯誤。導致異常的原因較多,如內存用盡、硬件故障、違反表的完整性約束、設計缺陷等。PL/SQL提供了異常錯誤處理機制,可以幫助實現對錯誤的捕獲和處理。當異常發生時,PL/SQL會自動地捕獲異常并將程序控制流程轉移到異常處理部分部會的程序。
語法:
EXCEPTION
WHEN 異常錯誤名稱1 [OR 異常錯誤名稱2……] THEN
語句段1;
WHEN 異常錯誤名稱3 [OR 異常錯誤名稱4…… ] THEN
語句段2;
……
WHEN OTHERS THEN
語句段3;
上述語法中,異常處理部分以保留字EXCEPTION開始,可以使用WHEN子句按“異常錯誤名稱”捕獲各種異常錯誤,其他沒有預計到的異常錯誤可以使用WHEN OTHERS子句進行捕獲。
針對一些常見的錯誤,PL/SQL預定義了一些異常錯誤。當PL/SQL程序違反了Oracle的規定或超出了系統規定的限制時,就會隱含地引發一個預定義的錯誤。PL/SQL在程序包STANDARD中包含了這些預定義異常,常用的預定義異常錯誤見表4-1-2所示。
表1.1.14-1-2 PL/SQL預定義異常
異常 | ORACLE錯誤 | 描述 |
access_into_null | ora-6530 | 試圖訪問一個未初始化的對象 |
case_not_found | ora-6592 | case語句中的選項與用戶輸入的數據不匹配 |
cursor_already_open | ora-6511 | 試圖打開一個已打開的游標 |
dup_val_on_index | ora-0001 | 試圖破壞一個唯一性約束 |
invalid_cursor | ora-1001 | 試圖打開一個無效的游標 |
invalid_number | ora-1722 | 試圖對非數字值進行數字操作 |
login_denied | ora-1017 | 無效的用戶名或者口令 |
no_data_found | ora-1403 | 查詢未找到數據 |
not_logged_on | ora-1012 | 還未連接就試圖數據庫操作 |
program_error | ora-6501 | 內部錯誤 |
rowtype_mismatch | ora-6504 | 主變量的游標的類型不兼容 |
storage_error | ora-6500 | 內部錯誤 |
timeout_on_resource | ora-0051 | 發生超時 |
too_many_rows | ora-1422 | select into 命令返回多行 |
transaction_backed_out | ora-006 | 由于死鎖提交被退回 |
value_error | ora-6502 | 轉換或者裁剪錯誤 |
zero_divide | ora-1476 | 試圖被除零 |
預定義異常都是由Oracle判斷的異常錯誤。在實際的PL/SQL程序開發過程中,為了具體的業務規則、編程和調試的需要,程序員可以自定義一些異常。自定義異常必須進行聲明,并且必須使用RAISE語句顯式地觸發。
在刪除表中的數據時,如果沒有符合條件的記錄,則不會刪除數據。因為這不是錯誤,所以不會有任何的錯誤提示,但可以使用自定義錯誤的方法來提示。例如,通過判斷來獲知是否存在該記錄,并使用自定義異常的方法進行提示,代碼如圖14.1.13所示。其中sql代表隱含游標。
設想網上購物的一次交易,其付款過程至少包括以下幾步數據庫操作:
? 更新客戶所購商品的庫存信息
? 保存客戶付款信息--可能包括與銀行系統的交互
? 生成訂單并且保存到數據庫中
? 更新用戶相關信息,例如購物數量等等
正常的情況下,這些操作將順利進行,最終交易成功,與交易相關的所有數據庫信息也成功地更新。但是,如果在這一系列過程中任何一個環節出了差錯,例如在更新商品庫存信息時發生異常、該顧客銀行帳戶存款不足等,都將導致交易失敗。一旦交易失敗,數據庫中所有信息都必須保持交易前的狀態不變,比如最后一步更新用戶信息時失敗而導致交易失敗,那么必須保證這筆失敗的交易不影響數據庫的狀態--庫存信息沒有被更新、用戶也沒有付款,訂單也沒有生成。否則,數據庫的信息將會一片混亂而不可預測。
數據庫事務正是用來保證這種情況下交易的平穩性和可預測性的技術。
事務用于保證數據的一致性,它由一組相關的dml語句組成,該組的dml(數據操作語言insert delete update)語句要么全部成功,要么全部失敗。
對一組SQL語句操作構成事務,數據庫操作系統必須確保這些操作的原子性,一致性,隔離性,持久性.
1、 原子性(Atomicity)
事務的原子性是指事務中包含的所有操作要么全做,要么不做,也就是說所有的活動在數據庫中要么全部反映,要么全部不反映,以保證數據庫的一致性。
2、 一致性(Consistency)
事務的一致性是指數據庫在事務操作前和事務處理后,其中數據必須滿足業務的規則約束。 和我們的規則預期一致。 不會出現一個加 一個沒減
3、 隔離性(Isolation)
隔離性是指數據庫允許多個并發的事務同時對其中的數據進行讀寫或修改的能力,隔離性可以防止多個事務的并發執行時,由于它們的操作命令交叉執行而導致數據的不一致性。 Oracle支持 read commited 和序列化
4、 持久性(durability)
事務的持久性是指在事務處理結束后,它對數據的修改應該是永久的。即便是系統在遇到故障的情況下也不會丟失,這是數據的重要性決定的。
在Oracle數據庫中,沒有提供開始事務處理語句,所有的事務都是隱式開始的,也就是說在oracle中,用戶不可以顯示使用命令來開始一個事務.oracle任務第一條修改數據庫的語句,或者一些要求事務處理的場合都是事務的隱式開始。但是當用戶想要終止一個事務處理時,必須顯示使用commit和rollback語句結束。
Savepoint 在事務中建立一個存儲的點.當事務處理發生異常而回滾事務時,可指定事務回滾到某存儲點.然后從該存儲點重新執行。
Rollback 回滾事務 取消對數據庫所作的任何操作
Commit 提交事務 對數據庫的操作做持久的保存。
實例4.14:設置自動提交
SET AUTOCOMMIT {ON | OFF | IMMEDIATE | n}
IMMEDIATE選項的功能與ON相同
n表示當Oracle數據庫成功執行了n條insert,update,delete或PL/SQL程序塊時自動提交事務
SQL> set autocommit on;
SQL>show autocommit;
Commit語句用于提交事務
使用ROLLBACK語句可以將事務回滾到事務的起點或某個保存點開始
定義保存點
保存點定義了事務中的一個位置,使用Rollback語句可以將數據會滾到保存點的位置,從而實現事務的部分回滾功能。
savepoint <回滾點>
rollback to <回滾點>
查看事務信息
查看事務信息使用視圖V$TRANSACTION,這個視圖必須使用sys或system訪問,因為當前事務是匿名事務,所以name字段值為空
前面的實例都是匿名事務,其實可以給事務命名
SET TRANSACTION NAME '事務名稱'
通過plsql塊 演示事務declarebegin insert into dept values(33,'xx','ss');insert into dept values(10,'xx','ss');commit;exception when others thenrollback;end;4.1.1 事務和鎖
當多個用戶同時訪問Oracle數據庫,執行事務操作(dml語句)時,同時可能有多個用戶訪問同一個數據庫資源,Oracle會自動在被作用的表上加鎖,防止其他用戶的事務改表的數據,這里對我們用戶來說是非常重要的,它會避免使用的數據產生邏輯錯誤。
例如轉賬 可能出現負值。
如果沒有鎖定且多個用戶同時訪問一個數據庫,則當他們的事務同時使用相同的數據時可能會發生問題。由于并發操作帶來的數據不一致性包括:丟失數據修改、讀”臟”數據(臟讀)、不可重復讀、產生幽靈數據。
(1)丟失數據修改
當兩個或多個事務選擇同一行,然后基于最初選定的值更新該行時,會發生丟失更新問題。每個事務都不知道其它事務的存在。最后的更新將重寫由其它事務所做的更新,這將導致數據丟失。如上例。 再例如,兩個編輯人員制作了同一文檔的電子復本。每個編輯人員獨立地更改其復本,然后保存更改后的復本,這樣就覆蓋了原始文檔。最后保存其更改復本的編輯人員覆蓋了第一個編輯人員所做的更改。如果在第一個編輯人員完成之后第二個編輯人員才能進行更改,則可以避免該問題。
(2)讀“臟”數據(臟讀)
讀“臟”數據是指事務T1修改某一數據,并將其寫回磁盤,事務T2讀取同一數據后,T1由于某種原因被除撤消,而此時T1把已修改過的數據又恢復原值,T2讀到的數據與數據庫的數據不一致,則T2讀到的數據就為“臟”數據,即不正確的數據。 例如:一個編輯人員正在更改電子文檔。在更改過程中,另一個編輯人員復制了該文檔(該復本包含到目前為止所做的全部更改)并將其分發給預期的用戶。此后,第一個編輯人員認為目前所做的更改是錯誤的,于是刪除了所做的編輯并保存了文檔。分發給用戶的文檔包含不再存在的編輯內容,并且這些編輯內容應認為從未存在過。如果在第一個編輯人員確定最終更改前任何人都不能讀取更改的文檔,則可以避免該問題。
( 3)不可重復讀
指事務T1讀取數據后,事務T2執行更新操作,使T1無法讀取前一次結果。不可重復讀包括三種情況: 事務T1讀取某一數據后,T2對其做了修改,當T1再次讀該數據后,得到與前一不同的值。
扣款。
(4)產生幽靈數據
按一定條件從數據庫中讀取了某些記錄后,T2刪除了其中部分記錄,當T1再次按相同條件讀取數據時,發現某些記錄消失 T1按一定條件從數據庫中讀取某些數據記錄后,T2插入了一些記錄,當T1再次按相同條件讀取數據時,發現多了一些記錄。
數據庫是一個多用戶使用的共享資源。當多個用戶并發地存取數據時,在數據庫中就會產生多個事務同時存取同一數據的情況。若對并發操作不加控制就可能會讀取和存儲不正確的數據,破壞數據庫的一致性。 加鎖是實現數據庫并發控制的一個非常重要的技術。當事務在對某個數據對象進行操作前,先向系統發出請求,對其加鎖。加鎖后事務就對該數據對象有了一定的控制,在該事務釋放鎖之前,其他的事務不能對此數據對象進行更新操作。
使用鎖解決不可重復讀 和丟失數據修改!!
在數據庫中有兩種基本的鎖類型:排它鎖(Exclusive Locks,即X鎖)和共享鎖(Share Locks,即S鎖)。當數據對象被加上排它鎖時,其他的事務不能對它讀取和修改。加了共享鎖的數據對象可以被其他事務讀取,但不能修改。數據庫利用這兩種基本的鎖類型來對數據庫的事務進行并發控制。
Oracle數據庫的鎖類型
根據保護的對象不同,Oracle數據庫鎖可以分為以下幾大類:DML鎖(data locks,數據鎖),用于保護數據的完整性;DDL鎖(dictionary locks,字典鎖),用于保護數據庫對象的結構,如表、索引等的結構定義;內部鎖和閂(internal locks and latches),保護數據庫的內部結構。
DML鎖的目的在于保證并發情況下的數據完整性,本文主要討論DML鎖。在Oracle數據庫中,DML鎖主要包括TM鎖和TX鎖,其中TM鎖稱為表級鎖,TX鎖稱為事務鎖或行級鎖。 粒度
當Oracle執行DML語句時,系統自動在所要操作的表上申請TM類型的鎖 用來預防其他事務使用ddl語句來修改表結構 刪除表等。當TM鎖獲得后,系統再自動申請TX類型的鎖,并將實際鎖定的數據行的鎖標志位進行置位。這樣在事務加鎖前檢查TX鎖相容性時就不用再逐行檢查鎖標志,而只需檢查TM鎖模式的相容性即可,大大提高了系統的效率。TM鎖包括了SS、SX、S、X等多種模式,在數據庫中用0-6來表示。不同的SQL操作產生不同類型的TM鎖。
在數據行上只有X鎖(排他鎖)。在 Oracle數據庫中,當一個事務首次發起一個DML語句時就獲得一個TX鎖,該鎖保持到事務被提交或回滾。當兩個或多個會話在表的同一條記錄上執行DML語句時,第一個會話在該條記錄上加鎖,其他的會話處于等待狀態。當第一個會話提交后,TX鎖被釋放,其他會話才可以加鎖。
當Oracle數據庫發生TX鎖等待時,如果不及時處理常常會引起Oracle數據庫掛起,或導致死鎖的發生,產生ORA-60的錯誤。這些現象都會對實際應用產生極大的危害,如長時間未響應,大量事務失敗等。
示例4.20:死鎖實例
因為大型數據庫應用系統存在并發機制,也就是說可能同時有多個會話訪問同一個數據,這時可能不可避免出現死鎖。例如有兩個事務A和B,如果事務A已經鎖定了數據庫對象A(數據庫對象A可能是一張表或表中的幾條記錄)。如果事務B也已經鎖定了數據庫對象B(數據庫對象B可能是一張表或表中的幾條記錄)。此時事務A再去申請鎖定數據庫對象B,而同時時事務B再去申請鎖定數據庫對象A。兩者互不相讓,就產生了死鎖,嚴重影響性能。
示例4.21:jdbc中的死鎖public static void main(String[] args) { Connection ct = null; try { // 1、加在驅動 Class.forName("oracle.jdbc.driver.OracleDriver"); // 得到連接 ct = DriverManager .getConnection( "jdbc:oracle:thin:@localhost:1521:orcl","scott","tiger"); // 從下面開始和sql一樣 // 加入事務處理 ct.setAutoCommit(false); Statement sm = ct.createStatement(); sm.executeUpdate("update dept set loc='shanghai' where deptno=10"); Thread.sleep(4000); sm.executeUpdate("update dept set loc='beijing' where deptno=20"); } catch (Exception e) { e.printStackTrace(); } finally{ System.out.println("事務1結束?。。?!"); try { ct.commit(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }創建第二個main函數,將Statement類對象sm執行的SQL語句調換一下,就可以模擬死鎖。
也可以設置隔離級別來達到控制并發的目的 其實隔離級別的原理就是使用不同的鎖策略來達到目的:
Read commited : 這種隔離級別指的是,事務只能讀取已經提交的數據,(但是支持可重復讀與幻讀)是oracle數據庫默認的隔離模式。
SEAIALIZABLE:不允許臟讀,重復讀與幻想讀,最高的隔離級別。這種隔離級別標明事務A在操作數據庫的時候好像就只有事務A在操作,沒有其他事務在操作數據庫一樣。
Oracle 中是這樣實現 SERIALIZABLE 事務的:原本通常在語句級得到的讀一致性現在可以擴展到事務級。也就是在事務執行的那一刻,將這個事務將要操作的數據拍了一張照片。
級別越高 并發性越低 完整性一致性越高。
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
l SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
? 本章總結
? PL/SQL是Oracle在標準SQL語言上的過程性擴展,它允許嵌入SQL語句、定義變量和常量、使用過程語言結構(條件分支語句和循環語句)、使用異常來處理Oracle錯誤等
? PL/SQL塊可以分為匿名塊、命名塊、子程序、程序包,觸發器5種
? 針對一些常見的錯誤,PL/SQL預定義了一些異常錯誤。當PL/SQL程序違反了Oracle的規定或超出了系統規定的限制時,就會隱含地引發一個預定義的錯誤
? 為了具體的業務規則、編程和調試的需要,程序員可以自定義一些異常。自定義異常必須進行聲明,并且必須使用RAISE語句顯式地觸發。
? 事務用于保證數據的一致性,它由一組相關的dml語句組成,該組的dml(數據操作語言insert delete update)語句要么全部成功,要么全部失敗。
? 事務控制語句包括commit,rollback,savepoint
任務實訓部分
1:PL/SQL塊中數據類型的使用
訓練技能點
? PL/SQL塊程序結構中的數據類型
需求說明
在使用記錄變量插入數據和更新數據時,需注意列的順序、個數、類型必須與記錄成員
的順序、個數、類型完全匹配。現要求實現:使用記錄變量的方式來插入部門信息。
實現思路
(1) 定義一個關于dept部門表的%ROWTYPE變量。
(2) 為其中的deptno部門編號、部門名稱及地址賦值。
(3) 然后通過INSERT語句插入數據。
關鍵代碼
PL/SQL塊中流程控制語句的使用
訓練技能點
? FOR循環的使用
需求說明
在PL/SQL中,可以使用FOR循環直接訪問SELECT查詢獲得的結果。要求查詢出各個部
門工資最高的雇員信息。
實現思路
(1) 通過FOR循環訪問各個部門,輸出dept表中所有部門的名稱
(2) 根據各個部門提供的部門編號(deptno)查詢emp表中該部門工資最高的雇員。
(3) 輸出該雇員信息。
通過For循環查詢獲得各個部門工資最高的雇員信息
異常處理
訓練技能點
? 異常處理
需求說明
使用非預定義異常,更新特定雇員的部門號,并處理ORA-02291錯誤。當定義Oracle錯誤和異常之間的關聯關系時,需要使用偽過程EXCEPTION_INIT。
實現思路
(1) 首先的定義部分定義異常。
(2) 使用progma exception_init(exception_name,exception_number)在異常和oracle錯誤之間建立關聯,這時要求用戶知道可能出現的錯誤號。
(3) 最終在異常處理部分捕捉并處理異常。
鞏固練習
一.選擇題
1. 數據庫中有兩種基本的鎖類型是( )
A. 排它鎖
B. 共享鎖
C. 只讀鎖
D. 更新鎖
2. 下列選項中,不能直接嵌入PL/SQL塊中的語句有( )。
A.SELECT
B.INSERT
C.CREATE TABLE
D.GRANT
E.COMMIT
3. 當SELECT INTO語句沒有返回行時,觸發的異常是
時( )。A.TOO_MANY_ROWS
B.VALUE_ERROR
C.NO_DATA_FOUND
D.不會觸發任何異常
4. 以下PL/SQL塊的輸出結果是( )
DECLARE
v_1 NUMBER(2);
v_2 NUMBER(3);
BEGIN
v_2:=CASE WHEN v_1 IS NULL THEN 10 ELSE 20 end;
DBMS_OUTPUT.PUT_LINE(‘v_2:’||v_2);
END;
A.10
B.0
C.20
D.語法錯誤
5. 以下PL/SQL塊的輸出結果是( )
BEGIN
FOR I IN 1..5 LOOP
DBMS_OUTPUT.PUT_LINE(‘*’);
END LOOP;
END;
A.**
B.***
C.*
*
*
D.不會觸發任何異常
二.
操作題上機練習由用戶輸入一個雇員編號,要求在emp表中查找是否存在與輸入的雇員編號對應的雇員。
1.如果存在,則有以下操作:
(1)輸出“查到此雇員”,并判斷其部門是否為“SALES”部門。
(2)如果是“SALES”部門,則輸出“此雇員屬于SALES部門”,并刪除對應的記錄;否則輸出“此雇員不屬于SALES部門,不能刪除!”。
2.如查不存在,則輸出“找不到此雇員!”。
新聞熱點
疑難解答