ODBC一、ODBC簡介開放數(shù)據(jù)庫互連(ODBC)是微軟提出的數(shù)據(jù)庫訪問接口標(biāo)準(zhǔn)。開放數(shù)據(jù)庫互連定義了訪問數(shù)據(jù)庫的API一個規(guī)范,這些API獨立于不同廠商的DBMS,也獨立于具體的編程語言。通過使用ODBC,應(yīng)用程序能夠使用相同的源代碼和各種各樣的數(shù)據(jù)庫進行交互。這使得開發(fā)者不需要以特殊的數(shù)據(jù)庫管理系統(tǒng)DBMS為目標(biāo),或者了解不同支撐背景的數(shù)據(jù)庫的詳細(xì)細(xì)節(jié),就能夠開發(fā)和發(fā)布客戶/服務(wù)器應(yīng)用程序。下面是ODBC應(yīng)用系統(tǒng)的體系結(jié)構(gòu)。 
二、ODBC句柄應(yīng)用程序運行后,為維護執(zhí)行的狀態(tài),ODBC 管理器和ODBC 驅(qū)動程序中必須保持足夠的控制信息。應(yīng)用程序要求ODBC 管理器和ODBC 驅(qū)動程序為ODBC環(huán)境、每個連接以及每個SQL語句分配描述/控制信息存儲空間,并返回指向各個存儲區(qū)的句柄供其使用。 (1)環(huán)境句柄:整個ODBC上下文的根句柄。標(biāo)識全程數(shù)據(jù)訪問控制信息的內(nèi)存結(jié)構(gòu),包括有效連接句柄以及當(dāng)前活動連接句柄。ODBC將環(huán)境句柄定義為HENV類型的變量。應(yīng)用程序使用單一的環(huán)境句柄,在連接到數(shù)據(jù)源以前必須申請該句柄。 (2)連接句柄:管理有關(guān)數(shù)據(jù)庫會話的所有信息。連接句柄標(biāo)識每個特定的連接信息的內(nèi)存結(jié)構(gòu)。ODBC將環(huán)境句柄定義為HDBC類型的變量。應(yīng)用程序在連接數(shù)據(jù)源之前申請連接句柄。每個連接句柄與環(huán)境句柄有關(guān),環(huán)境句柄上可以有多個與其有關(guān)的連接句柄。 (3)語句句柄:ODBC語句包括應(yīng)用訪問數(shù)據(jù)源的SQL語句和語句相關(guān)的管理信息,語句句柄標(biāo)識每個語句管理信息的內(nèi)存結(jié)構(gòu)。ODBC將語句句柄定義為HSTMT類型的變量。應(yīng)用程序在提交SQL請求之前也必須申請語句句柄。每個語句句柄與一個連接句柄有關(guān),每個連接句柄上可以有多個與其有關(guān)的語句句柄。 三、ODBC程序執(zhí)行流程? 分配環(huán)境句柄 基于ODBC3.X版本的應(yīng)用統(tǒng)一使用SQLAllocHandle來分配句柄。調(diào)用時設(shè)計不同的句柄類型就可以獲得該類型的句柄。但在API內(nèi)部實現(xiàn)上一般重新轉(zhuǎn)換為執(zhí)行SQLAllocEnv,SQLAllocConnect和SQLAllocStmt,這樣可以達(dá)到兼容和代碼重用作用。SQLAllocEnv:用來分配環(huán)境句柄。 例如:ret = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &oraclehenv); ? 分配連接句柄 SQLAllocConnect:用來分配連接句柄。連接句柄提供對一些信息的訪問,例如,在連接上的有效語句及標(biāo)識符句柄,以及當(dāng)前是否打開一些一個事務(wù)處理。調(diào)用SQLAllocConnect 函 數(shù) 獲 取 連 接 句 柄。例如: ret = SQLAllocHandle(SQL_HANDLE_DBC, oraclehenv, &oraclehdbc); ? 建立數(shù)據(jù)源 使用已分配的連接句柄來建立應(yīng)用程序和數(shù)據(jù)源/數(shù)據(jù)庫系統(tǒng)的連接,進行句柄和數(shù)據(jù)源的綁定。綁定也由目標(biāo)數(shù)據(jù)源的ODBC驅(qū)動程序完成。 例 如:ret = SQLConnect(oraclehdbc, "conn",SQL_NTS, //ODBC的DNS名稱 "scott",SQL_NTS, //用戶賬號 "123",SQL_NTS); //密碼 ? 分配語句句柄 用戶對DBC數(shù)據(jù)源的存取操作,都是通過SQL語句實現(xiàn)的。在這個過程中,應(yīng)用程序 將通過連接向ODBC數(shù)據(jù)庫提交SQL語句,以完成用戶請求的操作。即通過執(zhí)行SQLAllocHandle或SQLAllocStmt來分配語句句柄。調(diào)用SQLAllocStmt 函數(shù)獲取語句句柄。例如:
SQLstmt= "SELECT * FROM authors" rc= SQLAllocStmt(hdbc, hstmt) ? 執(zhí)行SQL語句 執(zhí)行SQL語句。 執(zhí)行SQL 語 句 的方法比較多, 最簡單明了的方法是調(diào)用SQLAllocStmt函數(shù),例如: SQLstmt= "SELECT * FROM authors" rc= SQLExecDirect(hstmt, SQLstmt, Len(SQLstmt)) 如果SQL語句被順利提交并正確執(zhí)行,那么就會產(chǎn)生一個結(jié)果集。檢索結(jié)果集的方法有很多,最簡單最直接的方法是調(diào)用SQLFetch 和SQLGetData 函 數(shù)。 SQLFetch函數(shù)的功能是將結(jié)果集的當(dāng)前記錄指針移至下一個記錄; SQLGetData函數(shù)的功能是提取結(jié)果集中當(dāng)前記錄的某個字段值。通常可以采用一個循環(huán)以提取結(jié)果集中所有記錄的所有字段值,該循環(huán)重復(fù)執(zhí)行SQLFetch和SQLGetData函數(shù),直至SQLFetch函數(shù)返回SQL_NO_DATA_FOUND, 這表示已經(jīng)到達(dá)結(jié)果集的末尾。 DimColVal As String * 225 ColVal= String(255, 0) ? 結(jié)束應(yīng)用程序 在應(yīng)用程序完成數(shù)據(jù)庫操作, 退出運行之前,必須釋放程序中使用的系統(tǒng)資源。這些系統(tǒng)資源包括:語句句柄、連接句柄和ODBC環(huán)境句柄。完成這個過程的如下: 調(diào)用SQLFreeStmt 函數(shù)釋放語句句柄及其相關(guān)的系統(tǒng)資源。例如: rc= SQLFreeStmt(hstmt, SQL_DROP) 調(diào)用SQLDisconnect 函數(shù)關(guān)閉連接。 例 如: rc= SQLDisconnect(hdbc) 調(diào)用SQLFreeConnect函數(shù)釋放連接句柄及其相關(guān)的系統(tǒng)資源。例如: rc= SQLFreeConnect(hdbc) 調(diào)用SQLFreeEnv函數(shù)釋放環(huán)境句柄及其相關(guān)的系統(tǒng)資源,停止ODBC 操作。 例如: rc= SQLFreeEnv(henv) (7)錯 誤 處 理 所有DBCAPI函 數(shù), 若在執(zhí)行期間發(fā)生錯誤, 都將返回一個標(biāo)準(zhǔn)錯誤代碼SQL_ERROR。 一般來講,在每次調(diào)用ODBC API 函 數(shù) 之 后, 都應(yīng)該檢查該函數(shù)返回值,確定該函數(shù)是否成功地執(zhí)行,再決定是否繼續(xù)后續(xù)過程。 而詳細(xì)的錯誤信息,可以調(diào)用SQLError 函數(shù)獲得。SQLError 函數(shù)將返回下列信息: 標(biāo)準(zhǔn)的ODBC錯誤狀態(tài)碼 ODBC 數(shù)據(jù)源提供的內(nèi)部錯誤編碼錯誤信息串 四、開發(fā)環(huán)境的配置1.創(chuàng)建Oracle ODBC數(shù)據(jù)源 對于WIN 7系統(tǒng)來說,打開控制面板,找到ODBC,具體位置如下圖所示,如果沒有找到,可以在右上角搜索欄里面輸入ODBC,就可以找到了。 對于WIN XP系統(tǒng)來說,打開控制面板,找到管理工具,找到數(shù)據(jù)源(ODBC),顯示ODBC數(shù)據(jù)源管理器對話框。對話框如下圖所示。 2.設(shè)置和配置一個系統(tǒng)DSN,單擊“系統(tǒng)DSN標(biāo)簽”,選擇“添加”。 

 3.找到需要配置的數(shù)據(jù)源,單擊完成,彈出如下對話框,  
4.輸入數(shù)據(jù)源的名稱,一個簡單的描述,用戶名和網(wǎng)絡(luò)連接名。點擊確認(rèn)。  五、學(xué)生表創(chuàng)建1.首先創(chuàng)建stu表 create table stu( sno char(11) , sname varchar2(10), sex char(2), sage number, sdepart varchar2(30) ); 六、數(shù)據(jù)類型  
 七、參考資料數(shù)據(jù)庫系統(tǒng)概論 第四版 王珊 薩師煊 高等教育出版社 電子資料鏈接:http://pan.baidu.com/s/1su9c5
ODBC程序 開發(fā)工具vs2017<database.h> #pragma once
#ifndef _DATABASE_H
#define _DATABASE_H
#include <sql.h>
#include<sqlext.h>
#include<sqltypes.h>
typedef struct {
SQLHENV oraclehenv; //環(huán)境句柄
SQLHDBC oraclehdbc; //連接句柄
SQLHSTMT oraclehsmt; //語句句柄
SQLRETURN ret; //結(jié)果集
}DATABASE;
DATABASE getConnection(); //獲取連接
void init(DATABASE *d); //初始化
void freeConnection(DATABASE d); //釋放連接資源
#endif // !_DATABASE_H
<student.h> #pragma once
#include "DATABASE.h"
#ifndef _STUDENT_H
#define _STUDENT_H
#include <sql.h>
#include<sqlext.h>
#include<sqltypes.h>
#define sno_length 11
#define sname_length 10
#define sdepart_length 30
#define ssex_length 5
typedef struct {
SQLCHAR sno[sno_length], sname[sname_length], sdepart[sdepart_length], ssex[ssex_length];
SQLSMALLINT sage;
SQLINTEGER cbsno, cbsname, cbdepart, cbsage, cbsex;
}STUDENT;
SQLCHAR *get(SQLCHAR *p, char *s); //將char數(shù)組轉(zhuǎn)換SQLCHAR類型
void processSQL(SQLCHAR *sql, SQLHSTMT oraclehsmt);
void display(DATABASE d);
void getStu(char *sno, SQLHSTMT oraclehsmt);
int insert(STUDENT, DATABASE);
void deleteStu(char *sno, DATABASE d);
SQLRETURN updateStu(STUDENT s, DATABASE d);
STUDENT inputStu();
void error(SQLRETURN err, int n);
#endif // !_DATABASE_H
<getConnection.cpp> #include"DATABASE.h"
#include <sql.h>
#include<sqlext.h>
#include<sqltypes.h>
#include<stdlib.h>
#include <stdio.h>
#include<windows.h>
#include<string.h>
DATABASE getConnection() {
DATABASE d;
/****分配環(huán)境句柄********/
d.ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &d.oraclehenv);
d.ret = SQLSetEnvAttr(d.oraclehenv, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
/********建立連接*********/
d.ret = SQLAllocHandle(SQL_HANDLE_DBC, d.oraclehenv, &d.oraclehdbc);
d.ret = SQLConnect(d.oraclehdbc, (SQLCHAR *)"con", SQL_NTS, (SQLCHAR *)"HR", SQL_NTS, (SQLCHAR *)"oracle", SQL_NTS);
if (SQL_SUCCEEDED(d.ret))
{
puts("Connect Sucess!");
init(&d);
}
else
{
//連接失敗時返回錯誤值
puts("Conect Fail!");
}
return d;
}
void init(DATABASE *d)
{
/***初始化句柄*/
SQLEndTran(SQL_HANDLE_DBC, d->oraclehdbc, SQL_COMMIT); //提交事務(wù)
d->ret = SQLAllocHandle(SQL_HANDLE_STMT, d->oraclehdbc, &d->oraclehsmt); //初始化語句句柄
d->ret = SQLSetStmtAttr(d->oraclehsmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)SQL_BIND_BY_COLUMN, SQL_IS_INTEGER);//設(shè)置語句選項
}
void freeConnection(DATABASE d)
{
SQLEndTran(SQL_HANDLE_DBC, d.oraclehdbc, SQL_COMMIT); //提交事務(wù)
SQLFreeHandle(SQL_HANDLE_STMT, d.oraclehsmt);
SQLDisconnect(d.oraclehdbc);
SQLFreeHandle(SQL_HANDLE_DBC, d.oraclehdbc);
SQLFreeHandle(SQL_HANDLE_ENV, d.oraclehenv);
printf("釋放連接\n\n");
}
<operateStudent.cpp> #include "DATABASE.h"
#include "STUDENT.h"
#include <sql.h>
#include<sqlext.h>
#include<sqltypes.h>
#include<stdlib.h>
#include <stdio.h>
void processSQL(SQLCHAR *sql, SQLHSTMT oraclehsmt)
{
STUDENT s;
int count = 1;
s.cbsno = SQL_NTS;
s.cbsname = SQL_NTS;
s.cbdepart = SQL_NTS;
s.cbsage = 0;
s.cbsex = SQL_NTS;
SQLRETURN ret = SQLExecDirect(oraclehsmt, sql, SQL_NTS);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
ret = SQLBindCol(oraclehsmt, 1, SQL_C_CHAR, s.sno, sno_length, &s.cbsno);
ret = SQLBindCol(oraclehsmt, 2, SQL_C_CHAR, s.sname, sname_length, &s.cbsname);
ret = SQLBindCol(oraclehsmt, 3, SQL_C_CHAR, s.ssex, ssex_length, &s.cbsex);
ret = SQLBindCol(oraclehsmt, 4, SQL_C_LONG, &s.sage, 0, &s.cbsage);
ret = SQLBindCol(oraclehsmt, 5, SQL_C_CHAR, s.sdepart, sdepart_length, &s.cbdepart);
}
/***處理結(jié)果**/
while ((ret = SQLFetch(oraclehsmt)) != SQL_NO_DATA_FOUND )
{
if (ret == SQL_ERROR)
{
printf("erro!\n");
}
else
{
printf("\t%-3d %s %s %s %4d %s\n", ++count, s.sno, s.sname, s.ssex, s.sage, s.sdepart);
}
}
}
void display(DATABASE d)
{
SQLCHAR *sql = (SQLCHAR *)"select * from stu";
processSQL(sql, d.oraclehsmt);
}
/*****插入********/
int insert(STUDENT s, DATABASE d)
{
char str[100] = "insert into stu values(";
char *age = (char *)malloc(sizeof(s.sage) + 1);
_itoa_s((int)s.sage, age, 10, 10);
strcat_s(str, sizeof(str), "'");
strcat_s(str, sizeof(str), (char *)s.sno);
strcat_s(str, sizeof(str), "',");
strcat_s(str, sizeof(str), "'");
strcat_s(str, sizeof(str), (char *)s.sname);
strcat_s(str, sizeof(str), "',");
strcat_s(str, sizeof(str), "'");
strcat_s(str, sizeof(str), (char*)s.ssex);
strcat_s(str, sizeof(str), "',");
strcat_s(str, sizeof(str), "'");
strcat_s(str, sizeof(str), age);
strcat_s(str, sizeof(str), "',");
strcat_s(str, sizeof(str), "'");
strcat_s(str, sizeof(str), (char *)s.sdepart);
strcat_s(str, sizeof(str), "')");
d.ret = SQLExecDirect(d.oraclehsmt, (SQLCHAR *)str, SQL_NTS);
error(d.ret, 77);
return 0;
}
SQLCHAR *get(SQLCHAR *p, char *s)
{
if ((s == NULL) || (p == NULL))
{
return NULL;
}
SQLCHAR *r = p;
while ((*r++ = *s++) != '\0');
return p;
}
void getStu(char *sno, SQLHSTMT oraclehsmt)
{
SQLCHAR *sql;
char str[100] = "select * from stu where sno = \'";
strcat_s(str, sizeof(str), sno);
strcat_s(str, sizeof(str), "'");
sql = (SQLCHAR *)str;
printf("getStu()函數(shù)\n");
getchar();
processSQL(sql, oraclehsmt);
}
void deleteStu(char *sno, DATABASE d)
{
SQLCHAR *sql = NULL;
char str[100] = "delete from stu where sno = \'";
strcat_s(str, sizeof(str), sno);
strcat_s(str, sizeof(str), "'");
sql = (SQLCHAR *)str;
d.ret = SQLExecDirect(d.oraclehsmt, sql, SQL_NTS);
error(d.ret, 114);
}
SQLRETURN updateStu(STUDENT s, DATABASE d)
{
SQLRETURN ret;
SQLCHAR *sql = NULL;
char str[100] = "update stu set ";
char *age = (char *)malloc(sizeof(s.sage) + 1);
_itoa_s((int)s.sage, age, 10, 10);
strcat_s(str, sizeof(str), "sname = \'");
strcat_s(str, sizeof(str), (char *)s.sname);
strcat_s(str, sizeof(str), "', ");
strcat_s(str, sizeof(str), "sex = \'");
strcat_s(str, sizeof(str), (char *)s.ssex);
strcat_s(str, sizeof(str), "', ");
strcat_s(str, sizeof(str), "sage = \'");
strcat_s(str, sizeof(str), age);
strcat_s(str, sizeof(str), "', ");
strcat_s(str, sizeof(str), "sdepart = \'");
strcat_s(str, sizeof(str), (char *)s.sdepart);
strcat_s(str, sizeof(str), "' ");
strcat_s(str, sizeof(str), "where sno = \'");
strcat_s(str, sizeof(str), (char *)s.sno);
strcat_s(str, sizeof(str), "'");
for (int i = 0; i < sizeof(str); i++)
{
printf("%c", str[i]);
}
printf("\n");
sql = (SQLCHAR *)str;
ret = SQLExecDirect(d.oraclehsmt, sql, SQL_NTS);
error(ret, 150);
return ret;
}
STUDENT inputStu()
{
STUDENT s;
char sno[sno_length], sname[sname_length], ssex[ssex_length], sdepart[sdepart_length], ssage[5];
int sage;
fflush(stdin);
printf("請輸入一個學(xué)號:");
gets_s(sno, sizeof(sno));
printf("\n請輸入一個姓名:");
gets_s(sname, sizeof(sname));
printf("\n請輸入一個性別:");
gets_s(ssex, sizeof(ssex));
printf("\n請輸入一個年齡:");
sage = atoi(gets_s(ssage));
printf("\n請輸入一個部門:");
gets_s(sdepart, sizeof(sdepart));
get(s.sno, sno);
get(s.sname, sname);
get(s.ssex, ssex);
s.sage = sage;
get(s.sdepart, sdepart);
return s;
}
void error(SQLRETURN err, int n) {
printf("%d ", n);
switch (err) {
case SQL_SUCCESS:puts("****SQL_SUCCESS*****"); break;
case SQL_SUCCESS_WITH_INFO:puts("SQL_SUCCESS_WITH_INFO"); break;
case SQL_ERROR:puts("SQL_ERROR"); break;
case SQL_INVALID_HANDLE:puts("SQL_INVALID_HANDLE"); break;
case SQL_NO_DATA_FOUND:puts("SQL_NO_DATA_FOUND"); break;
case SQL_NEED_DATA:puts("SQL_NEED_DATA"); break;
default:puts("err");
}
}
<Test.cpp> #include "STUDENT.h"
#include "DATABASE.h"
#include <sql.h>
#include<sqlext.h>
#include<sqltypes.h>
#include<stdlib.h>
#include <stdio.h>
#include<windows.h>
#include<string.h>
char menu()
{
char choice;
printf("\t a.查詢4所有人的信息\n");
printf("\t s.查詢個人信息指定學(xué)號\n");
printf("\t i.插入\n");
printf("\t d.刪除\n");
printf("\t u.修改\n");
printf("\t q.退出\n");
printf("\n **********************\n \t請輸入你的選項:");
choice = getchar();
return choice;
}
void deal(char choice, DATABASE d)
{
getchar();
switch (choice)
{
init(&d);
case 'a':display(d);break;
case 's': {
char sno[10];
fflush(stdin);
printf("\n請輸入學(xué)號:");
gets_s(sno);
printf("sno = %s\n", sno);
getStu(sno, d.oraclehsmt); break;
}
case 'i': {
STUDENT s = inputStu();
insert(s, d);break;
}
case 'd': {
char sno[10];
printf("請輸入學(xué)號:");
gets_s(sno);
deleteStu(sno, d); break;
}
case 'u': {
STUDENT s = inputStu();
updateStu(s, d);break;
}
case 'q': freeConnection(d); exit(0);
default:printf("輸入錯誤,請從新輸入\n"); break;
}
printf("\n\t***************處理結(jié)束******************\n");
}
int main()
{
DATABASE database = getConnection();
do
{
char c;
c = menu();
deal(c,database);
getchar();
system("cls");
} while (true);
return 0;
}
<sql> drop table stu;
create table stu(
sno char(10),
sname varchar2(10),
sex char(5),
sage number,
sdepart varchar2(30),
primary key(sno)
);
insert into stu values('201500730','張三','男',20,'計算機系' );
insert into stu values('201500731','李四','男',20,'計算機系' );
insert into stu values('201500732','王五','男',20,'計算機系' );
insert into stu values('201500733','趙六','男',20,'計算機系' );
commit;
select * from stu;
|