程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 一個好用的ODBC數據庫類CMYODBC

一個好用的ODBC數據庫類CMYODBC

編輯:關於VC++

一、引言

感覺MFC的CRecordset類不是很好用,因為我們要想使用的話必須為每個查詢從CRecordset類派生出一個新類,或者進行動態數據交換。在VC知識庫第六期上面有一篇介紹"單獨使用CRecordset"文章,可是上面的CRecordset打開方式只能使用CRecordset::forwardOnly,游標只能向前滾動,而且用這種方式,你根本無法從打開的記錄集中獲得本次查詢得到了有多少列。有一次在應用的時候,我只好通過捕獲CRecordset::GetFieldValue()的異常來得到查詢的結果有多少列。為了使用的方便,我自己寫了一個數據庫類CMYODBC,它是用ODBC API寫的,它支持各種sql語句,支持事務處理。它最好的地方在於,對於查詢的記錄集實現了動態綁定,這是通過類CODBCSet來實現的。要說明的是,這兩個類可以說比較簡單,兩個類的代碼量很少,所以建議感興趣的朋友看一下它的代碼,下圖是本代碼運行效果圖:

二、原理

其實無論是使用ODBC API還是使用ORACLE的OCI(對於ORACLE的OCI感興趣的朋友,歡迎一起探討,OCI的功能很強大,支持動態綁定,支持pl/sql,它的類的封裝和CMYODBC很相似,用它來代替ODBC編程,可以解決ODBC的效率問題)其過程都很相似,一般分為以下幾個過程:

1 初始化工作環境

2 連接數據源

3 操作數據源

4 檢索結果集

5 更新結果集

6 事務處理

7 斷開連接,釋放各種句柄

大家都知道在使用CDatabase時候,如果要執行的是select語句的話,那麼要通過CRecordset來檢索結果集,而CRecordset類要我們先選擇表等來先進行綁定,這樣我們使用的時候很不方便,其實我們根本不需要這樣做,而且我們也不需要知道這次執行的是關於那個數據庫那張表的sql語句,因為在執行完SQLExecDirect()後,可以通過調用SQLNumResultCols() 、SQLColAttribute()等函數來獲得執行的結果的很多屬性,如這次執行的結果集是多少列、每列的字段名、列的類型等,然後根據類型可以動態分配內存,然後在用這些內存去綁定,最後能過SQLFetch()來得到結果集。在CMYODBC這個類裡是通過CODBCSet類應用上面的原理來實現自動綁定的。

下面介紹一下類CMYODBC的使用方法:

1  通過調用ConnectDB(const char *cpServerName, const char *cpUserName, const char *cpPassword)函數來聯接數據庫。其中的參數意義如下:

cpServerName-----ODBC數據源名

cpUserName-------用戶名

cpPassword-----口令

2  通過調用ExeSqlDirect(const char *cpSqlStmt)函數可以執行一些操作數據源的語句,如修改、刪除語句等。其中的參數意義如下: cpSqlStmt------你要執行的sql語句,如delete from emp where deptno < 20

3  如果要執行事務的話,調用ExecTrans(CStringList &strSqlList)函數,其中的參數 strSqlList表示你要執行的一系列sql語句。

4 如果要執行select語句的話,通過下面的步驟:

I 聲明一個CODBCSet 對象,如 CODBCSet rSet;

II然後調用函數PrepareSql(const char *cpSql, CODBCSet &rset),其中的參數的意義如下:

cpSql----代表要執行的select語句

rset-----表示一個CODBCSet的引用,你要把上面聲明的對象傳遞進去。

III調用FetchData()函數來取得結果集。

5 通過調用函數DisConnect()斷開和數據源的連接。

三、實例練習

下面就通過上面的例子一起來看一下這個類到底怎麼樣,為了方便,我建了一個簡單的access數據庫test.mdb,在這個數據庫中也只有一張表emp,它有三個字段。在下面的工程的InitInstance ()中,通過代碼為它自動建立了一個叫做"daliu"的ODBC數據源。

步驟一:

新建一個基於對話框的工程,命名為demo1,打開stdafx.h文件,加入#include 從例子中把MyODBC.h,MyODBC.cpp, ODBCSet.h, ODBCSet.cpp復制到這個工程的目錄下,並且加入到工程中,方法是菜單project->add to project->files,選擇這四個文件就可以了。復制test.mdb文件,把它加入到這個工程的debug目錄下。也可以是其它的目錄,只要和你的執行程序在同一個目錄就可以了。

步驟二:

參照上面的對話框,在上面加入按鈕和一個ClistCtrl控件,在classwizard上面關聯控件的變量ClistCtrl關聯m_list控件,為三個EDIT分別關聯CString類型的m_strID,m_strName,m_strJob.

步驟三:

在CDemo1App::InitInstance()的最上面,加入下面的代碼,實現自動ODBC數據源的增加。

char path[MAX_PATH] = {''\0''};
GetModuleFileName(NULL,path,MAX_PATH);//得到執行文件名
m_strExePath.Format("%s", path);
int iPosition;
iPosition = m_strExePath.ReverseFind(''\\'');
m_strExePath = m_strExePath.Left(iPosition + 1);
CString strAccessPath = m_strExePath + "test.mdb";//得到這個數據庫文件的路徑
int iLen = strAccessPath.GetLength();
char cpConfig[MAX_PATH];
//由於在這個聯結串中有靠\0來分開數據源每個配置信息項的,所以只好用下面的笨方法了。
strcpy(cpConfig, "DSN=daliu\0");
strcpy(cpConfig + 10, "DBQ=");
strcpy(cpConfig + 14, strAccessPath);
strcpy(cpConfig + 14 + iLen, "\0");
strcpy(cpConfig + 15 + iLen, "DEFAULTDIR=");
strcpy(cpConfig + 15 + iLen + 11, m_strExePath);
strcpy(cpConfig + 25 + iLen + m_strExePath.GetLength(), "\0\0");
if(!SQLConfigDataSource(NULL,ODBC_ADD_SYS_DSN,
  "Microsoft Access Driver (*.mdb)\0",cpConfig))//設置odbc數據源

步驟四:

設置Clistctrl控件的風格,為他加入圖象資源。 首先要在CDemo1Dlg中加入#include"ODBCSet.h"#include"MyODBC.h",然後在CDemo1Dlg中添加成員變量CimageList ImageList;添加成員函數BOOL ShowData() 在CDemo1Dlg::OnInitDialog()中加入下面的代碼:

ImageList.Create(16,16,ILC_COLOR8,0,5);
ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON1));
DWORD dwStyle=GetWindowLong(m_list.GetSafeHwnd(),GWL_STYLE);
dwStyle |= LVS_REPORT;
SetWindowLongA(m_list.GetSafeHwnd(),GWL_STYLE,dwStyle);
m_list.SetExtendedStyle(LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT|LVS_EX_TRACKSELECT);
m_list.SetImageList(&ImageList, LVSIL_SMALL);
ShowData()//這個函數是用來向列表框中插入數據的。

下面我們來分析一下ShowData()函數,它是使用CMYODBC的關鍵。

BOOL CDemo1Dlg::ShowData()
{
  int i = 0, iCount;
  m_list.DeleteAllItems();//首先清空listview
  iCount = m_list.GetHeaderCtrl()->GetItemCount();
  for(i = 0; i < iCount; i++)
  {
    m_list.DeleteColumn(0);
  }
  for(i = 0; i < iCount; i++)
  {
    m_list.GetHeaderCtrl()->DeleteItem(0);
  }
  /*上面的代碼用於清空ClistCtrl控件中項,上面的兩個循環並不能合成一個,你可以試一下*/
  CString strSql;
  strSql = "select * from emp";//sql查詢語句
  CMyODBC db;  //聲明CMyODBC類的實例
  CODBCSet set;//聲明CODBCSet類的實例
  /*聯接數據庫,由於access數據庫沒有設定用戶和口//令,所以它們兩個就用空的字符串代替*/
  db.ConnectDB("daliu","", "");
  /*准備sql語句,你可以跟蹤一下,在這個函數中完成動態的綁定,得到共有幾列,每列的名稱等*/
  db.PrepareSql(strSql, set);
  for(i = 0; i < set.GetCols(); i++)/*set.GetCols()得到本次查詢得到了幾列。*/
  {
    m_list.InsertColumn(i, set.m_coldatafmt[i].name,LVCFMT_CENTER,80);
  }
  /*上面的循環用於插入列, m_coldatafmt是一個COL_DATAFMT_ODBC的結構,
  在我們調用db.PrepareSql()後,它就含有了每個列的名稱,字段數據類型,字段數據長度信息。*/
  /*下面的循環用於向列表框中插入數據, set.m_coldata是一個COL_DATA_ODBC的結構,
  當含有當前行的數據值,數據值的長度信息,這樣就實現了從記錄集中取數據的功能。*/
  int iRow = 0;
  while(db.FetchData())/*每次取回一條記錄。*/
  {
    for(i = 0; i < set.GetCols(); i++)
    {
      if(i == 0)
      {
        m_list.InsertItem(iRow, set.m_coldata[0].value);
      }
      else
      {
        m_list.SetItemText(iRow, i, set.m_coldata[i].value);
      }
    }
    iRow++;
  }
  set.Empty();/*清空記錄集*/
  db.DisConnect();/*斷開連接*/
return TRUE;  
}

下面我們再來看一個如何插入一條記錄:

void CDemo1Dlg::OnBtnadd()
{
  UpdateData(TRUE);
  CString strSql;
  strSql.Format("insert into emp values(%d,''%s'',''%s'')", atoi(m_strID), m_strName, m_strJob);
  CMyODBC db;
  db.ConnectDB("daliu","", "");//連接數據庫
  db.ExeSqlDirect(strSql);//執行sql語句
  db.DisConnect();//斷開連接
  this->ShowData();//刷新數據
}

響應其它的按鈕的函數就不一一寫了,和上面的都差不多,希望通過它能給我們用VC的開發數據庫工程帶來一些方便。

四、總結

ODBC有很多用處,例如我們可以把很多信息按照一定的格式保存在文本中(因為在商業上用別人的數據庫都是要買的),然後通過ODBC把這些文本文件映射成表,這些文件的目錄就成為一個數據庫,這些我們就可以很方便的對這些文件的內容通過sql來操作查詢,這樣開發的效率會高一些,而且是在本地,速度完全可以滿足。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved