ODBC 接口

ODBC(Open Database Connectivity,開放數(shù)據(jù)庫連接)是 Microsoft公司為應(yīng)用程序訪問關(guān)系型數(shù)據(jù)庫時提供的一組標(biāo)準(zhǔn)接口規(guī)范。ODBC對不同的關(guān)系型數(shù)據(jù)庫提供了統(tǒng)一的API,使用該AP來訪問任何提供了ODBC驅(qū)動程序的數(shù)據(jù)庫。

ODBC的構(gòu)成

  • 應(yīng)用程序-> 執(zhí)行調(diào)用ODBC接口,ODBC AP不能直接訪問數(shù)據(jù)庫,必須通過驅(qū)動程序管理器與數(shù)據(jù)庫交換信息。

  • 驅(qū)動程序-> 每種數(shù)據(jù)庫引擎都提供自己的ODBC驅(qū)動程序,并且需要向ODBC驅(qū)動程序管理器注冊

  • 驅(qū)動程序管理器-> ODBC提供了一個驅(qū)動程序管理器來管理對多個DBMS的同時訪問。

  • 數(shù)據(jù)源-> 包含了數(shù)據(jù)庫位置和數(shù)據(jù)庫類型等信息,實際上是種數(shù)據(jù)連接的抽象。

ODBC的優(yōu)點

以統(tǒng)一的方式處理所有的數(shù)據(jù)庫,ODBC開發(fā)的程序可以在不同的關(guān)系型數(shù)據(jù)庫(SQL Server,Mysql,Oracle,HGDB等)之間自由切換。

功能強大豐富,提供了異步操作,事務(wù)處理等高級功能。

開發(fā)環(huán)境搭建

軟件 版本
HGDB 安全版V4、企業(yè)版v5及以上版本
IDE visual Studio 2019

前提條件

連接瀚高數(shù)據(jù)庫需要使用瀚高的ODBC驅(qū)動程序,下面介紹如何在外網(wǎng)下載瀚高的ODBC和其使用方法。

通過百度網(wǎng)盤即可下載瀚高的ODBC(瀚高數(shù)據(jù)庫V4.5.4及之后版本安裝后會自帶ODBC驅(qū)動,驅(qū)動位置:/opt/HighGo4.5.4-see/etc/drivers/ODBC)

鏈接:https://pan.baidu.com/s/1CrUNnRJqFXUG9gODR6WMXA

提取碼:5rbm

下載解壓之后會生成ODBC_FT2000.tar.gz、ODBC_Loongson.tar.gz、ODBC-Centos.rar、ODBC-Windows.rar 4個壓縮包,分別對應(yīng)飛騰、龍芯、CentOs、Windows

詳細(xì)對應(yīng)關(guān)系見下表:

驅(qū)動包名稱 對應(yīng)芯片
ODBC_FT2000.tar.gz 飛騰
ODBC_Loongson.tar.gz 龍芯
ODBC-Centos.rar Centos
ODBC-Windows.rar Windows

根據(jù)實際版本選擇對應(yīng)的ODBC驅(qū)動即可。

windows安裝

1、雙擊hgdbodbc-x86-64-20201028.msi直接安裝:

image.png

2、安裝完成后在控制面板–>管理工具:

image.png

3、點擊添加:

image.png

4、選擇PostgreSQL Unicode(64):

image.png

5、輸入數(shù)據(jù)庫信息,點擊test:

image-20220517103027083

6、出現(xiàn)以下信息說明連接成功:

image-20220517103514811

Linux安裝

1、本次使用V4.5.7版本

2、UNIX/Linux系統(tǒng)下的驅(qū)動程序管理器主要有unixODBC和iODBC,在這里使用unixODBC2.3.1作為連接數(shù)據(jù)庫的組件。

3、需要準(zhǔn)備unixODBC環(huán)境:

? 安裝unixODBC:執(zhí)行命令 yum install unixODBC 和 yum install unixODBC-devel

1、修改配置文件

進(jìn)入/opt/HighGo4.5.7-see/etc/drivers/ODBC/unixODBC/etc目錄修改odbcinst.ini、odbc.ini:

odbcinst.ini添加如下信息:

[HighGo]
Description = ODBC for HighGo
Driver = /opt/HighGo4.5.7-see/etc/drivers/ODBC/psqlODBC/lib/psqlodbcw.so
Driver64 = /opt/HighGo4.5.7-see/etc/drivers/ODBC/psqlODBC/lib/psqlodbcw.so
FileUsage =1

? odbc.ini添加如下信息:

[HighGo457]
Driver = HighGo
Description = HighGo DSN
Servername = 192.168.2.5
Database = test
Username = test
Password = test
Port = 5866
ReadOnly = No

注意:odbc.ini中的Driver對應(yīng)的是odbcinst.ini中最上邊中括號中的內(nèi)容。

2、測試連接

到/opt/HighGo4.5.7-see/etc/drivers/ODBC/unixODBC/bin目錄下執(zhí)行

說明:-v 的作用是,一旦報錯,可以展示報錯詳情

[root@centos-min4 bin]# ./isql -v HighGo457

+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+
SQL>

注意:需要添加環(huán)境變量ODBCSYSINI=/opt/HighGo4.5.7-see/etc/drivers/ODBC/unixODBC/etc

示例代碼

Odbc_Demo.cpp

//包含頭文件
#include<Windows.h>
#include <sql.h>
#include <sqlext.h>
#include<sqltypes.h>
#include <tchar.h>
#include <iostream>
using namespace std;

int main()
{
//設(shè)置為中文
_wsetlocale(LC_ALL, L"chs");

SQLRETURN ret = SQL_ERROR;

//分配ODBC環(huán)境句柄
SQLHENV hEnv = NULL;
ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);
if (SQL_SUCCESS == ret)
{
wcout << _T("環(huán)境句柄分配成功!") << endl;
}
else
{
return -1;
}

//設(shè)定ODBC的版本
ret = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);

//分配數(shù)據(jù)庫連接句柄
SQLHDBC hDbc = NULL;
ret = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc);

//根據(jù)DSN ,連接數(shù)據(jù)庫
ret = SQLConnect(hDbc, (SQLTCHAR*)_T("HighGoOdbc"), SQL_NTS, (SQLTCHAR*)_T("test"), SQL_NTS, (SQLTCHAR*)_T("test"), SQL_NTS);
if ((ret == SQL_SUCCESS) || (ret == SQL_SUCCESS_WITH_INFO))
{
wcout << _T("數(shù)據(jù)庫連接成功!") << endl;
}
else if (ret == SQL_ERROR)
{
SQLTCHAR state[128] = { 0 };
SQLTCHAR msg[128] = { 0 };
//獲取錯誤信息
ret = SQLError(hEnv, hDbc, NULL, state, NULL, msg, sizeof(msg), NULL);
wcout << state << " " << msg << endl;
}

//分配語句句柄
SQLHSTMT hStmt = NULL;
ret = SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt);

//////////-----插入數(shù)據(jù)--------start

//沒 “?”簡單版本
//SQLTCHAR insert_sql[] = _T("INSERT INTO student (name,age) VALUES('李白',23) ");
//ret = SQLPrepare(hStmt, insert_sql, SQL_NTS);


//復(fù)雜版本
SQLTCHAR insert_sql[] = _T("INSERT INTO student (name,age) VALUES(?,?) ");
ret = SQLPrepare(hStmt, insert_sql, SQL_NTS);

//復(fù)雜版本下的參數(shù)傳遞到SQL語句中
SQLTCHAR name[32];
SQLSMALLINT age=40;

//綁定SQL語句的參數(shù)
ret = SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR,SQL_CHAR, 50, 0, (SQLPOINTER)name,0, NULL);
ret = SQLBindParameter(hStmt, 2, SQL_PARAM_INPUT, SQL_C_SHORT, SQL_SMALLINT, 0, 0, (SQLPOINTER)&age, 0, NULL);

//name賦值
strcpy_s((char*)name, _countof(name), "Miller");

//執(zhí)行SQL語句
ret = SQLExecute(hStmt);
if ((ret == SQL_SUCCESS) || (ret == SQL_SUCCESS_WITH_INFO))
{
SQLLEN n = 0;
ret = SQLRowCount(hStmt, &n);//查詢被影響的行數(shù)
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
_tprintf(_T("插入%d行數(shù)據(jù)成功!\n"), n);
}
}
else if (ret == SQL_ERROR)
{
SQLTCHAR state[128] = { 0 };
SQLTCHAR msg[128] = { 0 };
//獲取錯誤信息,注意填寫語句句柄
ret = SQLError(hEnv, hDbc, hStmt, state, NULL, msg, sizeof(msg), NULL);
wcout << state << " " << msg << endl;
}

//////////-----插入數(shù)據(jù)--------end


//////////-----查詢數(shù)據(jù)--------start

//SQL查詢語句
SQLTCHAR select_sql[] = _T("SELECT * FROM student ");

//執(zhí)行SQL語句
ret = SQLExecDirect(hStmt, select_sql, SQL_NTS); //SQL_NTS自動計算sql語句的長度
if ((ret == SQL_SUCCESS) || (ret == SQL_SUCCESS_WITH_INFO))
{
//查詢之后,所有數(shù)據(jù)放到了一塊緩沖區(qū),我們需要把他分離出來
int id = 0;
CHAR name[32] = { 0 };
short age = 0;
//綁定字段
SQLLEN len = SQL_NTS;
SQLBindCol(hStmt, 1, SQL_C_LONG, &id, sizeof(id), 0);
SQLBindCol(hStmt, 2, SQL_C_CHAR, &name, sizeof(name), &len);
SQLBindCol(hStmt, 3, SQL_C_SHORT, &age, sizeof(age), 0);
//逐行遍歷,獲取數(shù)據(jù)
ret = SQLFetch(hStmt);
while (ret != SQL_NO_DATA)
{
wcout << id << "\t" << name << "\t" << age << endl;
//每次清除一下上行的舊數(shù)據(jù),保證下次獲取的數(shù)據(jù)干凈
id = 0;
ZeroMemory(name, sizeof(name));
age = 0;
//獲取下一行緩沖區(qū)的數(shù)據(jù)填充到id,name,age
ret = SQLFetch(hStmt);
}

SQLLEN n = 0;
ret = SQLRowCount(hStmt, &n);//查詢被影響的行數(shù)(適用于SELECT ,INSERT,UPDATE,DELETE操作)
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
_tprintf(_T("查詢%d行數(shù)據(jù)成功!\n"), n);
}
}
else if (ret == SQL_ERROR)
{
SQLTCHAR state[128] = { 0 };
SQLTCHAR msg[128] = { 0 };
//獲取錯誤信息,注意填寫語句句柄
ret = SQLError(hEnv, hDbc, hStmt, state, NULL, msg, sizeof(msg), NULL);
wcout << state << " " << msg << endl;
}

///////// -----查詢數(shù)據(jù)--------end

//釋放語句句柄
if (hStmt)
{
ret = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
}

//關(guān)閉數(shù)據(jù)庫連接
ret = SQLDisconnect(hDbc);
if (ret == SQL_SUCCESS)
{
wcout << _T("關(guān)閉數(shù)據(jù)庫連接成功!") << endl;
}

//釋放連接句柄
if (hDbc)
{
ret = SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
}

//釋放環(huán)境句柄
if (hEnv)
{
ret = SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
}

return 0;
}

執(zhí)行結(jié)果:

image-20220427224911938

image-20220427224928520