,歡迎訪問網頁設計愛好者web開發。
linux/unix下odbc的安裝、配置與編程
齊亮 ([email protected])
2002 年 7 月
本文主要內容是介紹odbc的簡單原理,以及如何在linux/unix下進行odbc的安裝、配置與編程。
一、 odbc原理
odbc 是open database connect 即開放數據庫互連的簡稱,它是由microsoft 公司于1991 年提出的一個用于訪問數據庫的統一界面標準,是應用程序和數據庫系統之間的中間件。它通過使用相應應用平臺上和所需數據庫對應的驅動程序與應用程序的交互來實現對數據庫的操作,避免了在應用程序中直接調用與數據庫相關的操作,從而提供了數據庫的獨立性。
odbc 主要由驅動程序和驅動程序管理器組成。驅動程序是一個用以支持odbc 函數調用的模塊,每個驅動程序對應于相應的數據庫,當應用程序從基于一個數據庫系統移植到另一個時,只需更改應用程序中由odbc 管理程序設定的與相應數據庫系統對應的別名即可。驅動程序管理器可鏈接到所有odbc 應用程序中,它負責管理應用程序中odbc 函數與dll 中函數的綁定。
odbc 使用層次的方法來管理數據庫,在數據庫通信結構的每一層,對可能出現依賴數據庫產品自身特性的地方,odbc 都引入一個公共接口以解決潛在的不一致性,從而很好地解決了基于數據庫系統應用程序的相對獨立性,這也是odbc 一經推出就獲得巨大成功的重要原因之一。
從結構上分,odbc 分為單束式和多束式兩類。
單束式驅動程序
單束式驅動程序介于應用程序和數據庫之間,像中介驅動程序一樣數據提供一個統一的數據訪問方式。
當用戶進行數據庫操作時,應用程序傳遞一個odbc 函數調用給odbc 驅動程序管理器,由odbc api 判斷該調用是由它直接處理并將結果返回還是送交驅動程序執行并將結果返回。
由上可見,單束式驅動程序本身是一個數據庫引擎,由它直接可完成對數據庫的操作,盡管該數據庫可能位于網絡的任何地方。 多束式驅動程序
多束式驅動程序負責在數據庫引擎和客戶應用程序之間傳送命令和數據,它本身并不執行數據處理操作而用于遠程操作的網絡通信協議的一個界面。
前端應用程序提出對數據庫處理的請求,該請求轉給odbc 驅動程序管理器,驅動程序管理器依據請求的情況,就地完成或傳給多束驅動程序,多束式驅動程序將請求翻譯為特定廠家的數據庫通信接口(如oracle 的sqlnet)所能理解的形式并交于接口去處理,接口把請求經網絡傳送給服務器上的數據引擎,服務器處理完后把結果發回給數據庫通信接口,數據庫接口將結果傳給多束式odbc 驅動程序,再由驅動程序將結果傳給應用程序。
很多程序員已經體會到了在windows平臺下的odbc的益處,而在linux/unix下進行數據庫編程的時候卻不得不根據不同的數據庫來選擇特有的api進行編程,一旦數據庫發生了改變,所有與這些api相關的程序都必須進行修改。其實在linux/unix下現在也有了自己的odbc,可以使我們的數據庫編程就像在windows平臺下一樣簡單。
下面我們開始介紹linux/unix下的odbc:
二、 linux/unix下odbc的安裝:
方法一:
先下載最新的unixodbc源碼包(http://www.unixodbc.org/unixodbc-2.2.1.tar.gz)放到/usr/local下,然后運行下述命令:
tar zxvf unixodbc-2.2.1.tar.gzcd unixodbc-2.2.1 ./configure --prefix=/usr/local/unixodbc-2.2.1 --includedir=/usr/include --libdir=/usr/
lib -bindir=/usr/bin --sysconfdir=/etcmakemake install
安裝成功后,unixodbc所需的頭文件都被安裝到了/usr/inlucde下,編譯好的庫文件安裝到了/usr/lib下,與unixodbc相關的可執行文件安裝到了/usr/bin下,配置文件放到了/etc下。
方法二:
下載rpm包進行安裝,我們這里以red hat 7.3為例:
unixodbc-2.2.0-5 rpm for i386(安裝包及源碼包)
(ftp://speakeasy.rpmfind.net/linux/redhat/7.3/en/os/i386/redhat/rpms/unixodbc-2.2.0-5.i386.rpm、ftp://ftp.rpmfind.net/linux/redhat/7.3/en/os/i386/srpms/unixodbc-2.2.0-5.src.rpm)
unixodbc-devel-2.2.0-5 rpm for i386
(ftp://speakeasy.rpmfind.net/linux/redhat/7.3/en/os/i386/redhat/rpms/unixodbc-devel-2.2.0-5.i386.rpm)
直接將unixodbc-2.2.0-5.i386.rpm和unixodbc-devel-2.2.0-5.i386.rpm裝入系統就可以了,命令如下:
rpm -ivh unixodbc-2.2.0-5.i386.rpmrpm -ivh unixodbc-devel-2.2.0-5.i386.rpm
安裝好以后,所需的各個部分與上面所列的位置相同。
三、 linux/unix下odbc的配置:
運行odbcconfig程序(在/usr/bin下),如下圖:
圖一:odbcconfig主窗口
和windows下的odbc設置窗口是不是很像?我想大家都能看懂吧。
第一步:安裝數據庫的odbc驅動程序
drivers這一欄中用來設置數據庫的驅動程序,點擊add按鈕,會出現下圖:
圖二:odbcconfig driver properties窗口
name一欄填入數據庫驅動的名稱,description是數據庫驅動的描述,driver是用來選擇數據庫驅動程序的,setup是用來選擇數據庫驅動安裝程序的,如果你是按照上述安裝方法安裝的,這些程序都放在/usr/lib下,下面是數據庫驅動程序的列表:
數據庫數據庫驅動程序數據庫驅動安裝程序txtlibodbctxt.solibodbctxts.sonntplibnn.solibodbcnns.sominisqllibodbcmini.solibodbcminis.sopostgresqllibodbcpsql.solibodbcpsqls.somysql(注釋)libodbcmys.sosybase/ms sql(注釋)libtdss.sooracle(注釋)liboraodbcs.so
注釋:
mysql、sybase/ms sql和oracle的數據庫驅動可以在下列網址找到:
mysql http://www.unixodbc.org/myodbc.html
sybase/ms sql http://www.freetds.org
oracle http://www.easysoft.org
mysql的驅動程序myodbc-2.50.39-4 rpm for i386以及源碼包:
ftp://speakeasy.rpmfind.net/linux/redhat/7.3/en/os/i386/redhat/rpms/myodbc-2.50.39-4.i386.rpm
ftp://ftp.redhat.com/pub/redhat/linux/7.3/en/os/i386/srpms/myodbc-2.50.39-4.src.rpm
選擇好驅動程序之后,點擊"√"保存退出。
第二步:設置dsn
dsn分為user dsn、system dsn和file dsn三種,我們以system dsn為例。選中system dsn一欄以后,點擊add…按鈕就會見到下圖:
圖三:創建dsn選擇數據庫驅動
列表中會列出你已經安裝好的數據庫驅動程序,我這里只裝了mysql和postgresql,然后選擇你所要使用的驅動程序,然后點擊ok就會出現下圖:
圖四:dsn的設置
我這里使用的是mysql的數據庫驅動,不同的數據庫,這個窗口的內容會有所不同。name是數據源的名稱,description是描述,server可以選擇服務器,如果本機啟動了mysql就可以選擇localhost,如果port和socket有特殊要求,再根據實際情況進行修改,database是用來選擇數據庫的,下拉菜單不一定包含所有的數據庫,你可以把自己已經創建好的數據庫名稱填寫在這里。都配置好之后,點擊"√"保存退出。
這樣linux/unix下的odbc數據源就已經設置好了,大家還可以在odbcconfig程序的status欄中查看odbc的使用情況,在advanced欄中設置是否做日志或者啟動連接池,在about欄中,有一個linux/unix odbc的示意圖,在credits按鈕中可以看到所有開發者的名字的列表。 odbcconfig程序中所有有關數據庫驅動程序的信息被放在odbcinst.ini(在/etc下)文件中,有關dsn的信息被放在odbc.ini(在/etc下)文件中,大家有興趣的話,可以自己去觀察一下。
第三步:使用datamanager程序瀏覽數據庫
運行datamanager程序之后就可以查看drivers、system dsn和user dsn這幾項內容,,在瀏覽數據庫的時候,可以在右面的sql欄中輸入sql語句,然后點擊人形按鈕就可以運行sql語句,運行結果會在results一欄中顯示出來,具體情況可以見下圖:
圖五:使用datamanager瀏覽數據庫
第四步:使用isql程序查看數據庫
unixodbc還提供了命令臺下查看數據庫的程序,這就是isql,用法如下:
isql dsn [uid [pwd]] [options]dsn 數據源名稱uid 用戶idpwd 用戶密碼options:-b 批處理,沒有提示符的模式-dx 設置列之間的分隔符為x-w 將查詢結果輸出為html格式-c 第一行輸出列名--version 輸出isql的版本號
四、 linux/unix下odbc的編程:
1、使用unixodbc提供的odbc api進行編程:
在進行編程之前,我們來看一下odbc api中的常用數據類型與我們在c語言中使用的數據類型的對應關系:
類型標識符odbc數據類型c數據類型sql_c_charsqlchar *unsigned char *sql_c_sshortsqlsmallintshort intsql_c_ushortsqlusmallintunsigned short intsql_c_slongsqlintegerlong intsql_c_floatsqlrealfloatsql_c_doublesqldouble, sqlfloatdoublesql_c_binarysqlchar *unsigned char *sql_c_type_datesql_date_structstruct tagdate_struct {sqlsmallint year; sqlusmallint month; sqlusmallint day; } date_struct;sql_c_type_timesql_time_structstruct tagtime_struct {sqlusmallint hour; sqlusmallint minute; sqlusmallint second; } time_struct;
我們這里使用的數據庫名稱為test(dsn),這個dsn使用的用戶名是root,密碼為空,表的名稱是web,字段情況如下:
> 字段名數據類型idintegernamechar(40)sizeinteger
第一:設定odbc環境句柄并設置參數
首先我們需要聲明一個odbc環境句柄(sqlhenv),它可以用來獲得有關的odbc環境信息,我們需要調用sqlallochandle ( sql_handle_env, sql_null_handle, &v_od_env )來獲得這個句柄,v_od_env就是要分配的sqlhenv類型的環境句柄。
分配好句柄之后,你給它需要設定所使用的odbc版本,你可以調用sqlsetenvattr ( v_od_env, sql_attr_odbc_version, (void*)sql_ov_odbc3, 0 ),sql_attr_odbc_version是存放你定義的odbc版本號的變量,sql_ov_odbc3則說明你的程序使用的是odbc 3.0。
第二:設定連接句柄并設置超時參數
我們需要聲明一個連接句柄(sqlhdbc),用來存放數據庫連接信息的,調用sqlallochandle ( sql_handle_dbc, v_od_env, &v_od_hdbc )獲得連接句柄,v_od_hdbc就是要分配的sqlhdbc類型的連接句柄。
分配好之后,我們可以調用sqlsetconnectattr ( v_od_hdbc, sql_login_timeout, (sqlpointer *)5, 0 )來設定連接超時參數。
第三:連接數據庫
調用sqlconnect ( v_od_hdbc, (sqlchar*) "test", sql_nts, (sqlchar*) "root", sql_nts, (sqlchar*) "", sql_nts )連接我前面提到的數據庫,需要設定三個參數,就是數據庫名稱、用戶名和密碼(因為我的數據庫密碼為空,所以這里的密碼也為空),后面的sql_nts的位置應該寫入這些參數的長度,如果寫的是sql_nts就是讓sqlconnect來決定參數的長度。
第四:分配sql語句的句柄并進行查詢:
需要聲明一個sql語句的句柄(sqlhstmt),用來存放sql語句信息的,調用sqlallochandle ( sql_handle_stmt, v_od_hdbc, &v_od_hstmt )來獲得這個句柄,v_od_hstmt就是我們要分配的sqlhstmt類型的sql語句句柄。
我們的查詢語句是:
select name, id from web order by id
執行這條查詢語句之后,查詢結果可能有很多行,但每行只有兩列,分別對應name和id,它們的數據類型為integer和char*,在odbc中的數據類型標識符為sql_c_ulong和sql_c_char。我們需要先聲明這樣的兩個變量來存貯查詢結果:
sqlinteger v_od_id;char v_od_buffer[200];
然后我們需要使用sqlbindcol函數把查詢結果和我們定義的變量進行綁定:
sqlbindcol(v_od_hstmt,1,sql_c_char, &v_od_buffer,150,&v_od_err);sqlbindcol(v_od_hstmt,2,sql_c_ulong,&v_od_id,150,&v_od_err);
這里的v_od_err是用來存放錯誤信息編號的變量,類型也是sqlinteger。
接下來,我們調用sqlexecdirect來進行查詢:
sqlexecdirect ( v_od_hstmt, "select dtname,iduser from web order by iduser", sql_nts );
我們可以用sqlnumresultcols ( v_od_hstmt, &v_od_colanz )來獲得結果的列數,也可以用sqlrowcount( v_od_hstmt, &v_od_rowanz )來獲得結果的條數,v_od_colanz和v_od_rowanz分別存儲相應的結果,類型分別為sqlsmallint和sqlinteger。
在讀取結果之前,我們需要調用sqlfetch ( v_od_hstmt )語句,這個語句可以用來獲得第一條結果也可以用來都下一條,有點像next的感覺。然后我們就可以在v_od_id和v_od_buffer里面獲得每條記錄的結果了。
第五:關于關閉連接和釋放句柄
關閉數據庫的連接,調用sqldisconnect ( v_od_hdbc )就可以了,但在關閉數據庫之前需要先釋放sql語句的句柄,而且在關閉數據庫之后應該釋放連接句柄和odbc環境句柄,語句如下(按正常的順序):
sqlfreehandle(sql_handle_stmt,v_od_hstmt);sqldisconnect(v_od_hdbc);sqlfreehandle(sql_handle_dbc,v_od_hdbc);sqlfreehandle(sql_handle_env, v_od_env);
第六:關于上述情況中的錯誤信息處理
我們需要定義兩個變量:
long v_od_erg;sqlinteger v_od_err;
sqlallochandle、sqlsetenvattr、sqlsetconnectattr、sqlconnect、sqlexecdirect、sqlnumresultcols和sqlrowcount的調用結果都可以用v_od_erg來存儲,v_od_err可以獲得sqlbindcol中的錯誤信息。
第七:獲得本機的dsn信息
我們可以在聲明sqlhenv句柄之后,使用sqldatasources函數來獲得本機的dsn信息。程序如下:
void od_listdsn(void){char l_dsn[100],l_desc[100];short int l_len1,l_len2,l_next;l_next=sql_fetch_first;while( sqldatasources(v_od_env,l_next,l_dsn, sizeof(l_dsn),&l_len1, l_desc, sizeof(l_desc), &l_len2) == sql_success){printf("server=(%s) beschreibung=(%s)/n",l_dsn,l_desc);l_next=sql_fetch_next;}}
l_next變量是用來指定我們所要獲得的dsn的類別:
sql_fetch_first設定sqldatasources()函數找到第一個可用的數據源(可以是user dsn,也可以是systerm dsn)sql_fetch_first_user設定sqldatasources()函數找到第一個user dsnsql_fetch_first_system設定sqldatasources()函數找到第一個system dsnsql_fetch_next找到下一個數據源,至于數據源類型則要根據前面的定義
到這里,我們在unix的c語言下面進行odbc編程已經講完,上述odbc api需要引用以下幾個頭文件(這些文件已經安裝到/usr/include下了):
#include #include #include
另外如果大家使用gtk進行編程,由于到目前為止gtk還沒有加入專門處理數據庫的部件,所以大家可以在gtk中調用上述的odbc api即可。
這里附上例程供大家參考學習:
/* odbc.c testing unixodbc*/#include #include #include #include #include sqlhenv v_od_env; // handle odbc environmentlong v_od_erg; // result of functionssqlhdbc v_od_hdbc; // handle connectionchar v_od_stat[10]; // status sqlsqlinteger v_od_err,v_od_rowanz,v_od_id;sqlsmallint v_od_mlen,v_od_colanz;char v_od_msg[200],v_od_buffer[200];int main(int argc,char *argv[]){ // 1. allocate environment handle and register version v_od_erg=sqlallochandle(sql_handle_env,sql_null_handle,&v_od_env); if ((v_od_erg != sql_success) && (v_od_erg != sql_success_with_info)) { printf("error allochandle/n"); exit(0); } v_od_erg=sqlsetenvattr(v_od_env, sql_attr_odbc_version, (void*)sql_ov_odbc3, 0); if ((v_od_erg != sql_success) && (v_od_erg != sql_success_with_info)) { printf("error setenv/n"); sqlfreehandle(sql_handle_env, v_od_env); exit(0); } // 2. allocate connection handle, set timeout v_od_erg = sqlallochandle(sql_handle_dbc, v_od_env, &v_od_hdbc); if ((v_od_erg != sql_success) && (v_od_erg != sql_success_with_info)) { printf("error allochdb %d/n",v_od_erg); sqlfreehandle(sql_handle_env, v_od_env); exit(0); } sqlsetconnectattr(v_od_hdbc, sql_login_timeout, (sqlpointer *)5, 0); // 3. connect to the datasource "web" v_od_erg = sqlconnect(v_od_hdbc, (sqlchar*) "test", sql_nts, (sqlchar*) "root", sql_nts, (sqlchar*) "", sql_nts); if ((v_od_erg != sql_success) && (v_od_erg != sql_success_with_info)) { printf("error sqlconnect %d/n",v_od_erg); sqlgetdiagrec(sql_handle_dbc, v_od_hdbc,1, v_od_stat, &v_od_err,v_od_msg,100,&v_od_mlen); printf("%s (%d)/n",v_od_msg,v_od_err); sqlfreehandle(sql_handle_env, v_od_env); exit(0); } printf("connected !/n"); v_od_erg=sqlallochandle(sql_handle_stmt, v_od_hdbc, &v_od_hstmt); if ((v_od_erg != sql_success) && (v_od_erg != sql_success_with_info)) { printf("fehler im allocstatement %d/n",v_od_erg); sqlgetdiagrec(sql_handle_dbc, v_od_hdbc,1, v_od_stat,&v_od_err,v_od_msg,100,&v_od_mlen); printf("%s (%d)/n",v_od_msg,v_od_err); sqlfreehandle(sql_handle_env, v_od_env); exit(0); } sqlbindcol(v_od_hstmt,1,sql_c_char, &v_od_buffer,150,&v_od_err); sqlbindcol(v_od_hstmt,2,sql_c_ulong,&v_od_id,150,&v_od_err); v_od_erg=sqlexecdirect(v_od_hstmt,"select dtname,iduser from web order by iduser",sql_nts); if ((v_od_erg != sql_success) && (v_od_erg != sql_success_with_info)) { printf("error in select %d/n",v_od_erg); sqlgetdiagrec(sql_handle_dbc, v_od_hdbc,1, v_od_stat,&v_od_err,v_od_msg,100,&v_od_mlen); printf("%s (%d)/n",v_od_msg,v_od_err); sqlfreehandle(sql_handle_stmt,v_od_hstmt); sqlfreehandle(sql_handle_dbc,v_od_hdbc); sqlfreehandle(sql_handle_env, v_od_env); exit(0); } v_od_erg=sqlnumresultcols(v_od_hstmt,&v_od_colanz); if ((v_od_erg != sql_success) && (v_od_erg != sql_success_with_info)) { sqlfreehandle(sql_handle_stmt,v_od_hstmt); sqldisconnect(v_od_hdbc); sqlfreehandle(sql_handle_dbc,v_od_hdbc); sqlfreehandle(sql_handle_env, v_od_env); exit(0); } printf("number of columns %d/n",v_od_colanz); v_od_erg=sqlrowcount(v_od_hstmt,&v_od_rowanz); if ((v_od_erg != sql_success) && (v_od_erg != sql_success_with_info)) { printf("number of rowcount %d/n",v_od_erg); sqlfreehandle(sql_handle_stmt,v_od_hstmt); sqldisconnect(v_od_hdbc); sqlfreehandle(sql_handle_dbc,v_od_hdbc); sqlfreehandle(sql_handle_env, v_od_env); exit(0); } printf("number of rows %d/n",v_od_rowanz); v_od_erg=sqlfetch(v_od_hstmt); while(v_od_erg != sql_no_data) { printf("result: %d %s/n",v_od_id,v_od_buffer); v_od_erg=sqlfetch(v_od_hstmt); } ; sqlfreehandle(sql_handle_stmt,v_od_hstmt); sqldisconnect(v_od_hdbc); sqlfreehandle(sql_handle_dbc,v_od_hdbc); sqlfreehandle(sql_handle_env, v_od_env); return(0);}
2.qt下進行odbc編程
qt 3.0提供了data table、data browser和data view三個與數據庫相關的控件。你可以在qt的project設置你要連接的數據庫,driver一欄中選擇qodbc3即可,其它選項你一看就明白了。上述的三個數據庫控件的使用方法可以參見qt中相應文檔,也很好使用的。