Posted on 2009-03-30 16:16
Prayer 閱讀(737)
評論(0) 編輯 收藏 引用 所屬分類:
DB2
王隆彥
前 言
在用大型關(guān)系型數(shù)據(jù)庫DB2進(jìn)行具體開發(fā)時,存儲過程的編寫是經(jīng)常要考慮的問題之一。本文將結(jié)合實例,對使用CLI來開發(fā)DB2存儲過程進(jìn)行詳細(xì)闡述。
■DB2存儲過程
存儲過程(Store Procedure)是Client/Server應(yīng)用中的一種編程方式,主要是為了解決客戶端應(yīng)用訪問數(shù)據(jù)庫時可能出現(xiàn)的網(wǎng)絡(luò)負(fù)擔(dān)過重的問題。
一般意義上,DB2為存儲過程的編寫提供了三種方式(不包括直接使用DB2的Store Procedure Builder生成的方式):第一種是嵌入式SQL編程;第二種是CLI編程;第三種是純SQL編程。本文將重點介紹CLI編程。
■CLI編程
CLI(Call Level Interface)編程是DB2提供的一種編寫動態(tài)數(shù)據(jù)庫讀寫程序的方式。在CLI編程中,所有SQL語句都通過DB2提供的一組C語言函數(shù)來執(zhí)行,因此可以在Visual Studio中直接開發(fā)。下面,我們首先要簡單介紹一下CLI的工作過程和方式。
CLI程序主要由三個部分組成:首先是環(huán)境變量初始化過程,其次是語句的執(zhí)行,最后是環(huán)境變量的釋放。我們將通過一個具體的例子來討論這三個過程。
■開發(fā)實例
該例子的數(shù)據(jù)庫是DB2可以自動生成的Sample庫,例子所完成的操作是從數(shù)據(jù)庫中獲取ID等于輸入?yún)?shù)值的員工姓名,例子的整個過程雖然非常簡單,但已經(jīng)包含了CLI編程的基本思路和步驟。
1. 初始化環(huán)境變量
在CLI中有三個句柄,分別是環(huán)境句柄、連接句柄、語句句柄。在初始化過程中首先要對前兩個句柄逐一進(jìn)行獲取,獲取成功后可連接數(shù)據(jù)庫并獲取第三個句柄。
SQLRETURN ret;
SQLHENV henv; // 環(huán)境句柄
SQLHDBC hdbc; // 連接句柄
SQLHSTMT hstmt; // 語句句柄
SQLCHAR DBNAME[]="SAMPLE"; //數(shù)據(jù)庫名
SQLCHAR USERNAME[]="db2admin"; // 用戶名
SQLCHAR PSW[]="ibmdb2"; // 口令
ret=SQLAllocEnv(&&henv) //分配環(huán)境句柄
ret=SQLAllocConnect(henv,&&hdbc)
//分配連接句柄
ret=SQLSetConnectOption(hdbc,SQL_AUTOCOMMIT,SQL_AUTOCOMMIT_OFF)
//設(shè)置連接屬性
ret=SQLConnect(hdbc,DBNAME,SQL_NTS,USERNAME,SQL_NTS,PSW,SQL_NTS) //連接數(shù)據(jù)庫
ret=SQLAllocStmt(hdbc,&&hstmt)
//分配語句句柄
上面的每個函數(shù)都有返回值,如果函數(shù)成功,ret值為SQL_SUCCESS,否則將返回錯誤代碼。
2. 語句的執(zhí)行
語句的執(zhí)行分四個階段:首先準(zhǔn)備數(shù)據(jù)接收的緩沖區(qū),然后執(zhí)行準(zhǔn)備好的SQL語句,第三步是將語句句柄和數(shù)據(jù)緩沖區(qū)進(jìn)行綁定,最后獲取數(shù)據(jù)。程序如下:
char RowBuffer[100][200];
//數(shù)據(jù)緩沖區(qū),其大小可自定義
typedef struct sqldat
{ SQLCHAR ColumnName[50];
SQLSMALLINT BufferLength;
SQLSMALLINT NameLength;
SQLSMALLINT DataType;
SQLUINTEGER ColumnSize;
SQLSMALLINT FAR DecimalDigitsPtr;
SQLSMALLINT FAR NullablePtr;
} sqldata;
// 為第三步的綁定準(zhǔn)備一個數(shù)據(jù)結(jié)構(gòu)
sqldata RowDesc[100];
//用于綁定的變量,維數(shù)與緩沖區(qū)對應(yīng)
memset(RowBuffer,64,100200);
//給緩沖區(qū)賦初始值,可以用于最后判斷是否真正從數(shù)據(jù)庫中獲取了數(shù)據(jù),這一步也可以省略
char tempsql[100];
sprintf(tempsql,"select NAME from db2admin.STAFF where ID= %s ",Condition);
// Condition為變量值,可由用戶輸入
sql=(SQLCHAR ) tempsql;
ret=SQLPrepare(hstmt,sql,SQL_NTS)
// 執(zhí)行準(zhǔn)備
ret=SQLExecute(hstmt) // 執(zhí)行
執(zhí)行成功后可進(jìn)行綁定過程
SQLINTEGER nullindicator;
SQLINTEGER displaysize[MAX_COLUMN];
SQLSMALLINT i;
SQLSMALLINT num_columns;
SQLNumResultCols(hstmt,&&num_columns);
//準(zhǔn)備綁定用的相關(guān)變量
for(i=1;i< =num_columns;i++)
{
RowDesc[i-1].BufferLength=200;
SQLDescribeCol(hstmt,i, RowDesc[i-1].ColumnName,RowDesc[i-1].BufferLength,&&(RowDesc[i-1].NameLength),&&(RowDesc[i-1].DataType),&&(RowDesc[i-1].ColumnSize),RowDesc[i-1].DecimalDigitsPtr,RowDesc[i-1].NullablePtr);
SQLColAttribute(hstmt,(SQLSMALLINT)(i),SQL_DESC_DISPLAY_SIZE,NULL,0,NULL,&&displaysize[i-1]);
RowDesc[i-1].ColumnSize=max(displaysize[i-1],strlen((char)RowDesc[i-1].ColumnName))+1;
SQLBindCol( hstmt, (SQLSMALLINT)i,
SQL_C_CHAR,(SQLPOINTER)(RowBuffer[i-1]),RowDesc[i-1].ColumnSize,
&&nullindicator);
}//循環(huán)綁定
//綁定完成后,可以將數(shù)據(jù)讀至緩沖區(qū)
while(SQLFetch(hstmt)!=SQL_NO_DATA)
{
// SQLFetch函數(shù)將已經(jīng)獲取的數(shù)據(jù)存入緩沖區(qū)
//此處的操作方式與ESQL中的游標(biāo)類似,支持對結(jié)果集的操作
//每執(zhí)行一次SQLFetch函數(shù)會把當(dāng)前獲取的一行數(shù)據(jù)讀到緩沖區(qū)中
//RowBuffer[i]中將存放該行的第i 列數(shù)據(jù)值
//本例中只有一行數(shù)據(jù)
}
char m_name[10];
memcpy(m_name,RowBuffer[0],10);
//從緩沖區(qū)中將結(jié)果讀到用戶變量中
3. 釋放環(huán)境變量
在數(shù)據(jù)獲取完成后,可以將環(huán)境變量釋放掉,但要注意釋放的先后順序。
SQLFreeStmt(hstmt,SQL_DROP);
// 釋放語句句柄
SQLDisconnect(hdbc);//與數(shù)據(jù)庫斷開
SQLFreeConnect(hdbc);//釋放連接句柄
SQLFreeEnv(henv);//釋放環(huán)境句柄
經(jīng)過上面的步驟,就完成了對數(shù)據(jù)庫的讀取過程。
4. 生成目標(biāo)存儲過程
從上面的過程看,CLI編程無疑是非常復(fù)雜的,但如果我們使用一些輔助手段來組織整個過程,其編程過程和調(diào)試步驟將會大大簡化。本文的例子使用了微軟的Visual Studio 6.0來幫助組織。在Visual C++中用Wizard生成一個DLL工程,然后將數(shù)據(jù)庫的初始化、綁定、釋放三個過程函數(shù)化,并在相應(yīng)的地方調(diào)用函數(shù)。在調(diào)試時只需針對語句的執(zhí)行部分,合適的調(diào)試方式是不直接生成DLL,而先生成一個普通的EXE工程來完成所需的工作,待調(diào)試成功后將相關(guān)代碼移到DLL工程中。過程函數(shù)化的另一個好處是在編寫多個存儲過程時代碼重用率高,對于剛才提到的這種調(diào)試方式也很有利。使用Visual C++的優(yōu)點還有編譯和鏈接過程簡單,不用在命令行的方式下操作,也不需要去記憶許多復(fù)雜的參數(shù)。不過要記住將db2cli.lib包含進(jìn)工程中,否則在鏈結(jié)過程中會有錯誤,還要做的一件事是按DLL工程中的要求編輯工程中的def文件以提供函數(shù)的可調(diào)用出口。
在DLL生成并調(diào)試通過后,剩下的工作與ESQL編程方式中的相應(yīng)階段類似,要手工編輯一個DB2文件并執(zhí)行它,這里就不再復(fù)述了。