第一部分DB2系統管理命令node
1. Db2有域,實例,和數據庫三層的概念。程序員
2. 查看數據庫服務器中有幾個數據庫。包括網絡中數據庫的引用。web
進入數據庫安裝目錄下的bin目錄:C:\Program Files\IBM\SQLLIB\BINsql
執行db2 list database directory命令數據庫
3. 查看命令選項說明express
list command options 編程
4. 查看運行的數據庫服務器中關聯了多少個引用程序對數據庫的訪問。緩存
進入數據庫安裝目錄下的bin目錄:C:\Program Files\IBM\SQLLIB\BIN安全
db2 list applications命令服務器
能夠經過db2 force application(進程id) 殺死對應的進程。
5. 如何強制斷開應用程序和數據庫的鏈接。
進入數據庫安裝目錄下的bin目錄:C:\Program Files\IBM\SQLLIB\BIN
行下列的命令 db2 force applications 能夠強制斷開應用程序和數據庫的鏈接。
6. 如何備份數據庫
進入db2的操做環境,而後運行
backup database 數據庫別名 user 用戶名 using 密碼命令
7. 中止數據庫的服務器。
進入數據庫安裝目錄下的bin目錄:C:\Program Files\IBM\SQLLIB\BIN
或db2操做環境中,若是在db2操做環境中必須經過的db2 terminate命令終結db2操做環境中啓動的全部子進程(即中止全部命令行處理器回話)
再執行db2stop命令。
注意:
在執行此命令的時候,必須沒有應用程序或用戶和數據庫鏈接。
能夠在執行中止命令以前查看於db2服務器鏈接的應用程序和用戶。而後執行牽制斷開命令斷開鏈接的數據庫和用戶。
8. 如何從舊版本中把數據庫遷移到新的安裝版本中(在新版數據庫種運行下列代碼)
db2ckmig /e 數據庫別名 /l 驗證信息保存路徑 /u 用戶名 /p 密碼
MIGRATE database 數據庫別名 user 用戶名 using 密碼命令
9. 啓動DB2服務器
進入數據庫安裝目錄下的bin目錄:C:\Program Files\IBM\SQLLIB\BIN
或db2操做環境中
執行db2start命令
10. 關於命令行編輯器的使用
使用命令行編輯器以前要鏈接到一個數據庫。在該數據庫中能夠執行想要執行的命令和 SQL語句。
首先要啓動數據庫服務器。登錄到數據庫的服務器上。
而後用在 CA (配置助手)菜單欄上(在 所選 下面)選擇 使用嚮導添加數據庫。
添加的數據庫能夠是網絡中的已經運行的數據庫。
而後選擇手工配置至數據庫的鏈接
若是是網絡鏈接選TCP/IP,若是是本地的數據庫則選擇本地鏈接
還要知道數據庫服務器中所在的Ip和端口號碼,以及數據庫的名稱。
對於安全性的認證通常採用dbm自帶的安全認證。經過以上的配置完成數據庫的 鏈接。
注意若是不知道網絡中有那些數據庫能夠經過配置助手的發現功能搜索網絡中的 數據庫。能夠直接把網絡中已知系統中的數據庫搜索到。包括已經鏈接的數據庫和 沒有鏈接的數據庫
ii. 使用命令行處理器來配置數據庫的鏈接
數據庫服務器節點的概念:
爲了鏈接網絡上的數據庫服務器,訪問數據庫提出了節點的概念。一個節點惟一對 應一個網絡中的數據庫。因此不能重複。創建了節點後,能夠把節點與一個網絡數 據庫對應。創建一一之間的映射。注意這個數據庫必須是在節點對應的數據庫服務 器中存在的。
1) 在客戶機上配置TCP/IP的節點
catalog tcpip node 自定義節點名 remote ip地址 server 端口號
terminate(做用是刷新目錄的告訴緩存,若是不刷新,只能在重啓計算機後 纔會起做用)
2) 編目數據庫
catalog database 數據庫名稱(必須在網絡中已經存在)as 數據庫別名
at node nod名稱 authentication 鏈接數據庫時所採用的認證方法
(通常是 server或client)
terminate
3) 創建數據庫
create db dbName
4) 鏈接數據庫
經過以上的配置設置。數據庫服務進程會保存配置信息。
在db2的會話進程中能夠經過
connect to 數據庫的別名
鏈接數據庫。這是能夠執行sql語句;或用!開頭能夠執行操做系統的命令
用「\」能夠做爲多行的分割符。
5) 查看數據庫的結構信息命令
鏈接到數據庫後能夠查看數據庫的結構信息,包括有什麼表,什麼視圖,什麼觸發 器等等
1) 查看數據庫中有多少表或視圖
list tables;
2) 查看錶或試圖的結構
describe table tableName獲describe Select * from tableName
10. 數據的導入導出操做
首先鏈接上數據庫;
用export命令
格式以下:
Export to c:\org.txt of del messages d:\msgs.txt select * from org
數據來源 |
保存格式 |
數據保存的位置 |
操做狀況保存位置 |
1) 如何導出大對象
export to d:\myfile.del of del lobs to d:\lob\ lobfile lobs modified by
Lobs in file select * from emp_photo
該句的含義是將從「select * from emp_photo」中得到的數據放到「d:\myfile.del of
del」文件中存放的格式是del,其中大對象的位置存放在 d:\lob\,文件名是lobs。
最後modified by lobsinfile指明指定要將大對象(LOB)數據導出到 LOBS TO 子 句中所指定的位置。
2) 如何導入數據
import from D:\TABLE1.ixf of ixf lobs from d:\lob lobfile lobs modified by lobsinfile
savecount 1000 messages D:\msg.txt insert intoTABLE1
// 其中,savecount表示完成每1000條操做,記錄一次。將D:\TABLE1.ixf文件中 的數據以ixf格式導入到表table1中。並把d:\lob目錄下的文件是lobs的大對象文 件導入到表中
11. 如何執行批處理命令:
首先進現鏈接數據庫
db2 => connect to dbName user xxx using password
退出命令處理器:
db2 => quit
在dos環境下輸入sql腳本文件的路徑全名
c:\> db2 -tvf 文件名.sql
注意腳本的每一條命令以分號做爲結束標誌。命令之間永換行符進行分割。
查看要移動的數據庫的表空間。表空間是孩子,數據庫是父母,一個數據庫可有不少表表空間。一個表空間只能屬於一個數據庫。
List tablespaces
查看每一個表空間的屬性
有兩種方法
1) 利用dblook命令
db2look –d dbname –e –o db.sql –i username –w password
把數據庫名是dbname的數據庫的結構信息輸入到db.sql的腳本中,username
是鏈接數據庫時的用戶名,password時密碼
而後創建一個新的空數據庫。
再把sql腳本中connect to 新的數據庫名
再經過db2 -tvf db.sql運行db.sql的數據庫編程腳本。這樣就把原來的數據庫中全部表再新數據庫中創建。只是沒有數據
最後用export和import命令把數據導入新的數據庫。
2) 在特定的目錄下面執行db2move dbname export -u username -p password命
令
把整個數據庫移動到該目錄下自動創建的5個文件上
(db2move.lst;import.out;export.out;tabl.ixf;tab1.msg)
而後建立一個新的數據庫;
最後回到特定的目錄(有上述的5個文件),執行
db2move dbname import -u username -p password
第二種方法能夠把數據一次所有導入和導出,比較好。
13. 瞭解數據庫服務器的配置是必要的。在某些特定的時候有可能要根據應用程序的要求來 更改數據庫服務器的配置。
用命令db2 get dbm cfg命令來運行數據庫的配置的相關信息
14. 如何設置數據庫服務器的配置
db2 update dbm cfg using 參數名 參數值
15. 讀數據庫的配置
db2 get db cfg for dbname
16. 設定數據庫鏈接的配置
db2 update db cfg for o_yd using 參數名 參數值
刪除數據庫鏈接。(首先要斷開關聯到數據庫應用程序的鏈接)
drop db dbName
對於本地數據庫執行刪除
對於網絡數據庫刪除節點編目。
附錄:
選項 描述 當前設置
------ ---------------------------------------- ---------------
-a 顯示 SQLCA OFF
-c 自動落實 ON
-e 顯示 SQLCODE/SQLSTATE OFF
-f 讀取輸入文件 OFF
-l 將命令記錄到歷史文件中 OFF
-n 除去換行字符 OFF
-o 顯示輸出 ON
-p 顯示交互式輸入提示符 ON
-r 將輸出保存到報告文件 OFF
-s 在命令出錯時中止執行 OFF
-t 設置語句終止字符 OFF
-v 回送當前命令 OFF
-w 顯示 FETCH/SELECT 警告消息 ON
-x 不打印列標題 OFF
-z 將全部輸出保存到輸出文件 OFF
第二部分數據庫的sql語法
與Oracle一致
第三部分編寫存儲過程
本文以 DB2 開發人員的角度介紹了在 DB2 存儲過程開發中須要注意的事項和技巧。新手若是可以按照本文介紹的最佳實踐來開發存儲過程,能夠避免一些常見的錯誤,從而編寫出高效的程序。本文從初始化參數、遊標、異常處理、臨時表的使用以及如何尋找並 rebind 非法存儲過程等常見問題進行了着重討論,而且給出了示例代碼。
DB2 提供的強大功能可讓開發人員建立出很是高效穩定的存儲過程。但對於初學者來講,開發出這樣的程序並不容易。本文主要討論開發高效穩定的 DB2 存儲過程的一些經常使用技巧和方法。
讀者定位爲具備必定開發經驗的 DB2 開發經驗的開發人員。
讀者能夠從本文學習到如何編寫穩定、高效的存儲過程。並能夠直接使用文章中提供的 DB2 代碼,從而節省他們的開發和調試時間,提升效率。
本文以 DB2 開發人員的角度介紹了在 DB2 存儲過程開發中須要注意的事項和技巧。新手若是可以按照本文介紹的最佳實踐來開發存儲過程,能夠避免一些常見的錯誤,從而編寫出高效的程序。本文從初始化參數、遊標、異常處理、臨時表的使用以及如何尋找並 rebind 非法存儲過程等常見問題進行了着重討論,而且給出了示例代碼。
在存儲過程當中,開發人員可以聲明和設置 SQL 變量、實現流程控制、處理異常、可以對數據進行插入、更新或者刪除。同時,客戶應用(這裏指調用存儲過程的應用程序,它能夠是 JDBC 的調用,也能夠是 ODBC 和 CLI 等)和存儲過程之間能夠傳遞參數,而且從存儲過程當中返回結果集。其中,使用 SQL 編寫的 DB2 存儲過程是在開發中常見的一種存儲過程。本文主要討論此類存儲過程。
最佳實踐 1:在建立存儲過程語句中提供必要的參數
建立存儲過程語句(CREATE PROCEDURE)能夠包含不少參數,雖然從語法角度講它們不是必須的,可是在建立存儲過程時提供它們能夠提升執行效率。下面是一些經常使用的參數
允許 SQL (allowed-SQL)
允許 SQL (allowed-SQL)子句的值指定了存儲過程是否會使用 SQL 語句,若是使用,其類型如何。它的可能值以下所示:
若是沒有明確聲明 allowed-SQL,其默認值是 MODIFIES SQL DATA。不一樣類型的存儲過程執行的效率是不一樣的,其中 NO SQL 效率最好,MODIFIES SQL DATA 最差。若是存儲過程只是讀取數據,可是由於沒有聲明 allowed-SQL 使其被看成對數據進行修改的存儲過程來執行,這顯然會下降程序的執行效率。所以建立存儲過程時,應當明確聲明其 allowed-SQL。
返回結果集個數(DYNAMIC RESULT SETS n)
存儲過程可以返回 0 個或者多個結果集。爲了從存儲過程當中返回結果集,須要執行以下步驟:
在建立存儲過程時指定返回結果集的個數能夠幫助程序員驗證存儲過程是否返回了所期待數量的結果集,提升了程序的完整性。
最佳實踐 2:對輸入參數進行必要的的檢查和預處理
不管使用哪一種編程語言,對輸入參數的判斷都是必須的。正確的參數驗證是保證程序良好運行的前提。一樣的,在 DB2 中對輸入參數的驗證和處理也是很重要的。正確的驗證和預處理操做包括:
在 DB2 儲存過程開發中,如須要遇到對空(NULL)進行初始化,咱們可使用 COALESCE 函數。COALESCE函數返回第一個非空的參數,語法以下:
清單1:COALESCE 函數
.---------------. (1) V | >>-COALESCE-------(--expression----,--expression-+--)---------->< |
COALESCE函數會依次檢查輸入的參數,返回第一個不是NULL的參數,只有當傳入COALESCE函數的全部的參數都是NULL的時候,函數纔會返回NULL。例如, COALESCE(piName,''),若是變量piName爲NULL,那麼函數會返回'',不然就會返回piName自己的值。
下面的例子展現瞭如何對參數進行檢查何初始化。
Person表用來存儲我的的基本信息,其定義以下:
表1: Person
下面是用於向表Person插入數據的存儲過程的參數預處理部分代碼:
SET poGenStatus = 0;
SET piName = RTRIM(COALESCE(piName, '')); SET piRank = COALESCE(piRank, 0);
-- make sure all required input parameters are not null IF ( piNum IS NULL OR piName = '' OR piAge IS NULL ) THEN SET poGenStatus = 34100; RETURN poGenStatus; END IF;
|
表Person中num、name和age都是非空字段。對於name字段,多個空格咱們也認爲是空值,因此在進行判斷前咱們調用RTRIM和COALESCE對其進行處理,而後使用 piName = '',對其進行非空判斷;對於Rank字段,咱們但願若是用戶輸入的NULL,咱們把它設置成"0",對其咱們也使用COALESCE進行初始化;對於"Age"和"Num" 咱們直接使用 IS NULL進行非空判斷就能夠了。
若是輸入參數沒有經過非空判斷,咱們就對輸出參數poGenStatus設置一個肯定的值(例子中爲 34100)告知調用者:輸入參數錯誤。
下面是對參數初始化規則的一個總結,供你們參考:
1. 輸入參數爲字符類型,且容許爲空的,可使用COALESCE(inputParameter,'')把NULL轉換成'';
2. 輸入類型爲整型,且容許爲空的,可使用COALESCE(inputParameter,0),把空轉換成0;
3. 輸入參數爲字符類型,且是非空非空格的,可使用COALESCE(inputParameter,'')把NULL轉換成'',而後判斷函數返回值是否爲'';
4. 輸入類型爲整型,且是非空的,不須要使用COALESCE函數,直接使用IS NULL進行非空判斷。
最佳實踐 3:正確設定遊標的返回類型
前面咱們已經討論瞭如何聲明存儲過程的返回結果集。這裏咱們討論一下結果集返回類型的問題。結果集的返回類型有兩種:調用者(CALLER) 和客戶應用(CLIENT)。首先咱們看一下聲明這兩種遊標的例子:
CREATE PROCEDURE getPeople(IN piAge INTEGER) DYNAMIC RESULT SETS 2 READS SQL DATA LANGUAGE SQL BEGIN DECLARE rs1 CURSOR WITH RETURN TO CLIENT FOR SELECT name, age FROM person WHERE age<piAge; DECLARE rs2 CURSOR WITH RETURN TO CALLER FOR SELECT NAME, age FROM person WHERE age>piAge; OPEN rs1; OPEN rs2; END |
代碼中rs1遊標的DECLAER語句中包含WITH RETURN TO CLIENT子句,表示結果集返回給客戶應用(CLIENT)。rs2遊標的DECLARE語句中包含WITH RETURN TO CALLER子句,表示結果集返回給調用者(CALLER)。
遊標返回給調用者(CALLER)表示由存儲過程的調用者接收結果集,而不考慮調用者是不是另外一個存儲過程,仍是客戶應用。圖(1)中存儲過程PROZ若是聲明爲WITH RETURN TO CALLER,那麼結果集會返回給存儲過程PROY,Client Application是不會獲得PROZ返回的結果集的。
圖1:存儲過程遞歸調用
遊標返回給客戶應用(CLIENT)表示由發出最初 CALL 語句的客戶應用接收結果集,即便結果集由嵌套層次中的 15 層深的嵌套存儲過程發出也是如此。圖1中存儲過程 PROZ 若是聲明爲 WITH RETURN TO CLIENT,那麼結果集會返回給 Client Application。返回給客戶應用(CLIENT)的遊標聲明是咱們常用的,也是默認的結果集類型。
在聲明返回類型時,咱們要認真考慮一下,咱們須要把結果集返回給誰,以避免丟失返回集,致使程序錯誤。
最佳實踐 4:異常(condition)處理
在存儲過程執行的過程當中,常常由於數據或者其餘問題產生異常(condition)。根據業務邏輯,存儲過程應該對異常進行相應處理或直接返回給調用者。此處暫且將condition譯爲異常以方便讀者理解。實際上有些異常(condition)並不是是因爲錯誤引發的,下面將詳細講述。
當存儲過程當中的語句返回的SQLSTATE值超過00000的時候,就代表在存儲過程當中產生了一個異常(condition),它表示出現了錯誤、數據沒有找到或者出現了警告。爲了響應和處理存儲過程當中出現的異常,咱們必須在存儲過程體中聲明異常處理器(condition handler),它能夠決定存儲過程怎樣響應一個或者多個已定義的異常或者預約義異常組。聲明條件處理器的語法以下,它會位於變量聲明和遊標聲明以後:
清單4:聲明異常處理器
DECLARE handler-type HANDLER FOR condition handler-action |
異常處理器類型(handler-type)有如下幾種:
異常處理器能夠處理基於特定SQLSTATE值的定製異常,或者處理預約義異常的類。預約義的3種異常以下所示:
若是產生了NOT FOUND 或者SQLWARNING異常,而且沒有爲這個異常定義異常處理器,那麼就會忽略這個異常,而且將控制流轉向下一個語句。若是產生了SQLEXCEPTION異常,而且沒有爲這個異常定義異常處理器,那麼存儲過程就會失敗,而且會將控制流返回調用者。
如下示例聲明瞭兩個異常處理器。 EXIT處理器會在出現SQLEXCEPTION 或者SQLWARNING異常的時候被調用。EXIT處理器會在終止SQL程序以前,將名爲stmt的變量設爲"ABORTED",而且將控制流返回給調用者。UNDO處理器會將控制流返回給調用者以前,回滾存儲過程體中已經完成的SQL操做。
清單5:異常處理器示例
DECLARE EXIT HANDLER FOR SQLEXCEPTION, SQLWARNING SET stmt = 'ABORTED'; |
DECLARE UNDO HANDLER FOR NOT FOUND; |
若是預約義異常集不能知足需求,就能夠爲特定的SQLSTATE值聲明定製異常,而後再爲這個定製異常聲明處理器。語法以下:
清單6:定製異常處理器
DECLARE unique-name CONDITION FOR SQLSATE 'sqlstate' |
處理器能夠由單獨的存儲過程語句定義,也可使用由BEGIN…END塊界定的複合語句定義。注意在執行符合語句的時候,SQLSATE和SQLCODE的值會被改變,若是須要保留異常前的SQLSATE和SQLCODE,就須要在執行復合語句的第一個語句把SQLSATE和SQLCODE賦予本地變量或參數。
一般,咱們會爲存儲過程定義一個執行狀態的輸出參數(例如:poGenStatus)。
根據這個輸出狀態,能夠代表存儲過程是否正確執行完畢。咱們須要定義一些異常處理器爲這個輸出參數賦值。下面是一個例子:
清單7:定義爲輸出參數賦值的異常處理器
-- Generic Handler DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND BEGIN NOT ATOMIC -- Capture SQLCODE & SQLSTATE SELECT SQLCODE, SQLSTATE INTO hSqlcode, hSqlstate FROM SYSIBM.SYSDUMMY1;
-- Use the poGenStatus variable to tell the procedure -- what type of error occurred CASE hSqlstate WHEN '02000' THEN SET poGenStatus=5000; WHEN '42724' THEN SET poGenStatus=3; ELSE IF (hSqlCode < 0) THEN SET poGenStatus=hSqlCode; END IF; END CASE; END;
|
上面的異常處理器會在出現SQLEXCEPTION, SQLWARNING, NOT FOUND異常的時候觸發。異常處理器會取出當前的SQLCODE, SQLSTATE,而後根據它們的值來設置輸出參數(poGenStatus)的值。
咱們還能夠定製一些異常處理器。例如,咱們能夠定義一些對參數進行初始化的異常處理器。這裏,異常處理器能夠看做是一個供存儲過程本身調用的內部函數。下面是這種狀況的一個例子:
清單8:供存儲過程本身調用的內部函數
----------------------------------------------------- -- CONDITION declaration ----------------------------------------------------- -- (80100~80199) SQLCODE & SQLSTATE DECLARE sqlReset CONDITION for sqlstate '80100';
----------------------------------------------------- -- EXCEPTION HANDLER declaration ----------------------------------------------------- -- Handy Handler DECLARE CONTINUE HANDLER FOR sqlReset BEGIN NOT ATOMIC SET hSqlcode = 0; SET hSqlstate = '00000'; SET poGenStatus = 0; END; ………… ----------------------------------------------------- -- Procedure Body ----------------------------------------------------- SIGNAL sqlreset;
-- insert the record …………
|
上面定製的異常處理器負責對參數hSqlcode,hSqlstate和poGenStatus初始化。當咱們在程序中須要對它們初始化時,咱們只須要調用SIGNAL sqlreset就能夠了。
最佳實踐 5:合理使用臨時表
咱們在儲存過程開發中常用臨時表。合理的使用臨時表能夠簡化程序的編寫,提供執行效率,然而濫用臨時表一樣也會使得程序運行效率下降。
臨時表通常在以下狀況下使用:
1. 臨時表用於存儲程序運行中的臨時數據。例如,若是在一個程序中第一條查詢語句執行的結果會被後續的查詢語句用到,那麼咱們能夠把第一次查詢的結果存儲在一個臨時表中供後續查詢語句使用,而不是在後續查詢語句中從新查詢一次。若是第一條查詢語句很是複雜和耗時,那麼上面的策略是很是有效的。
2. 臨時表能夠用於存儲在一個程序中須要返回屢次的結果集。例如,程序中有一個很耗資源的多表查詢,同時,該查詢在程序中須要執行屢次,那麼就能夠把第一次查詢的結果集存儲在臨時保中,後續的查詢只須要查臨時表就能夠了。
3. 臨時表也能夠用於讓SQL訪問非關係型數據庫。例如,能夠編寫程序把非關係型數據庫中的數據插入到一個全局臨時表中,那麼咱們就能夠對其數據進行查詢。
咱們可以使用 DECLARE GLOBAL TEMPORARY TABLE 語句來定義臨時表。DB2的臨時表是基於會話的,且在會話之間是隔離的。當會話結束時,臨時表的數據被刪除,臨時表被隱式卸下。對臨時表的定義不會在SYSCAT.TABLES中出現 下面是定義臨時表的一個示例:
清單9:定義臨時表
DECLARE GLOBAL TEMPORARY TABLE gbl_temp LIKE person ON COMMIT DELETE ROWS NOT LOGGED IN usr_tbsp |
此語句建立一個名爲 gbl_temp 的用戶臨時表。定義此用戶臨時表 所使用的列的名稱和說明與 person 的列的名稱和說明徹底相同。
清單10:建立有兩個字段的臨時表
DECLARE GLOBAL TEMPORARY TABLE SESSION.TEMP2 ( ID INTEGER default 3, NAME CHAR(30) ) --WITH REPLACE NOT LOGGED; --IN USER_TEMP_01;
|
此語句建立了一個有兩個字段的臨時表。
理論上臨時表是不須要顯示DROP的,由於它是基於會話的,當臨時表基於的鏈接關閉的時候,臨時表也就不存在了。可是在實際開發中會有一些狀況須要咱們對臨時表加以注意。
一種狀況就是被調用的存儲過程的返回值是一個基於臨時表的結果集。當存儲過程執行完畢的時候,臨時表並不會消失,由於返回的結果集至關於一個指針,指向臨時表所在的內存地址,此時臨時表是不會被DROP掉的。這種狀況下,既不能在存儲過程當中刪除這個臨時表,也不該該由客戶應用顯示的刪除臨時表,這就容易出現一些問題。下面咱們經過一個例子來講明這個問題。
下面示例代碼是返回臨時表的存儲過程(get_temp_table):
清單11:返回臨時表的存儲過程
----------------------------------------------------- -- TEMPORARY TABLE & CURSOR declaration ----------------------------------------------------- DECLARE GLOBAL TEMPORARY TABLE SESSION.TEMP ( ID INTEGER, NAME CHAR(30) ) --WITH REPLACE NOT LOGGED;
P2: BEGIN
DECLARE R_CRSR CURSOR WITH RETURN TO CLIENT FOR SELECT * FROM SESSION.TEMP FOR READ ONLY;
INSERT INTO SESSION.TEMP VALUES(1,piName);
OPEN R_CRSR;
END P2;
|
存儲過程當中聲明瞭有兩個字段的臨時表TEMP,聲明瞭一個遊標R_CRSR返回臨時表中全部記錄,最後在臨時表中插入兩條記錄。
程序第一次執行的結果以下:
圖2:程序第一次執行的結果
能夠從圖中看出,運行結果是咱們指望的。那麼若是咱們再運行一次,會有什麼結果呢?下圖是其運行結果:
圖3:程序再次執行的結果
第二次執行的時候程序卻出錯了,這是由於在同一個鏈接中,臨時表並無被DROP掉,因此在第二次調用存儲過程的時候就會出現臨時表已經存在的錯誤。
另一種狀況,就是不少時候例如在websphere中經過JDBC鏈接數據庫時使用了鏈接池的技術,這帶來了一些效率的提高,同時在某些狀況下也容易讓人誤解。客戶應用程序中關閉了數據庫鏈接,可是並不必定真正關閉了數據庫鏈接,若是客戶應用程序使用了臨時表而數據庫鏈接並無關閉,那麼臨時表就不會被DROP。當鏈接池把這個鏈接分給另外一個客戶程序的時候,新的客戶程序仍然可使用舊的臨時表,這不是咱們但願的。若是想避免上述問題,能夠在建立臨時表時,加上WITH REPLACE;或者根據業務邏輯在合適的地方顯示的DROP臨時表。
下面是使用WITH REPLACE建立臨時表的執行狀況。
圖4:使用WITH REPLACE建立臨時表
能夠看出在一個鏈接裏面,屢次調用存儲過程get_temp_table,也不會出現問題。臨時表在某些狀況下也是須要避免使用的。你們知道臨時表是存放在內存中的,若是一個臨時表有上萬或者十幾萬條記錄,同時程序的併發數很大,那麼在內存中創建的臨時表耗費的資源就很龐大,此時數據庫的性能會急劇降低,甚至會致使數據庫崩潰。所以,你們在使用臨時表的時候,須要考慮它對資源的耗費,避免盲目使用臨時表。
最佳實踐 6:尋找並rebind 非法的存儲過程
存儲過程會由於其涉及和引用的對象發生了改變而致使其非法(invalid),例如:修改了表結構,致使引用該表的存儲過程非法,或者從新編譯一個存儲過程,會使調用這個存儲過程的父存儲過程非法。此時咱們須要對非法的存儲過程從新編譯(rebind)。可是,對非法的存儲過程進行rebind的時候,須要肯定其引用的對象是合法的,不然非法的存儲過程也不能rebind成功。
這裏咱們介紹一下發現和rebind非法存儲過程的方法。咱們是經過判斷SYSCAT.routines中VALID字段的值來查找非法存儲過程的。下面是查找非法存儲過程的一段代碼:
清單12:查找非法存儲過程
SELECT RTRIM(r.routineschema) || '.' || RTRIM(r.routinename) AS spname , ' ( '|| RTRIM(r.routineschema) || '.' || 'P'||SUBSTR(CHAR(r.lib_id+10000000),2)||' )' FROM SYSCAT.routines r WHERE r.routinetype = 'P' AND ((r.origin = 'Q' AND r.valid != 'Y') OR EXISTS ( SELECT 1 FROM syscat.packages WHERE pkgschema = r.routineschema AND pkgname = 'P'||SUBSTR(CHAR(r.lib_id+10000000),2) AND valid !='Y' ) ) ORDER BY spname;
|
得到的結果以下:
清單13:查找非法存儲過程的結果
SPNAME ---------------------------------- TEST.DEMO_INFO_8 (TEST. P3550884)
|
可使用下面的命令rebind它們
清單14:Rebind 非法存儲過程語法
rebind package packagename resolve any@ |
Packagename就是查詢結果中括號裏的值。例如,若是rebind上面查出來的存儲過程。咱們只須要執行下面語句
清單15:Rebind 非法存儲過程
rebind package TEST.P3550884 resolve any@ |
固然,若是此存儲過程程序自己有問題,須要先修改存儲過程代碼後再進行編譯。
相似的,經過下面的代碼能夠得到非法的視圖。
清單16:得到非法的視圖
SELECT RTRIM(viewschema) || '.' || RTRIM(viewname) AS viewname FROM SYSCAT.views WHERE valid = 'X' ORDER BY viewname;
|
本文介紹了咱們在 DB2 存儲過程開發中常常用到的一些技巧。同時這些技巧也是編寫優秀存儲過程的基本要求。本文介紹的一些技巧只是揭開了高效使用 DB2 的冰山一角。DB2 爲咱們提供了豐富和強大的功能。在使用 DB2 的時候,咱們應當深刻理解其原理,找出更多的最佳實踐與你們分享。