1、简介ODBC:
随着C/S结构体系在互联网运用广泛,不同数据库访问成了突出问题。在没有ODBC之前,不同的数据库(SQL server、MySQL、Oracle等)采用的标准不同,但当前绝大部分数据库全部或部分地遵从关系数据库概念 ,有了这些共同点,ODBC应用而生,它没有太过复杂,ODBC 是基于结构化查询语言(SQL),使用 SQL 可大大简 化其应用程序设计接口(API) 。只要数据厂商提供的开发包支持这个标准,那么开发人员通过 ODBC 开发的程序可以在不同的数据库之间自由转换。
2、ODBC结构:
3、ODBC API开发:
3.1、所需要的文件:
sql.h:包含有基本的 ODBC API 的定义。
sqlext.h:包含有扩展的 ODBC 的定义。
odbc32.lib:库文件。这些文件开发工具已提供,无需安装。
3.2、ODBC流程图:
3.3、ODBC句柄:
ODBC 中的句柄分为三类:环境句柄,数据库连接句柄, SQL 语句句柄。(每一种句柄需要申请,执行完后进行释放。详细的请 阅读ODBC API开发教程)。
3.4、部分函数:
SQLRETURN retcode;//返回值
SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
//连接句柄的参数设置
SQLRETURN SQLSetStmtAttr(SQLHSTMT StatementHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
//语句句柄的参数设置
SQLRETURN SQLFetchScroll(SQLHSTMT StatementHandle,SQLSMALLINT FetchOrientation, SQLINTEGER FetchOffset);
//可滑动光标进项查询(比SQLFetch多了两个参数)
SQLRETURN SQLConnect(SQLHDBC ConnecionHandle, SQLCHAR* ServerName, SQLSMALLINT NameLength1, SQLCHAR* UserName,SQLSMALLINT NameLength2, SQLCHAR* Authentication, SQLSMALLINT NameLength3); //SQLConnect数据库
SQLRETURN SQLExecDirect(SQLHSTMT StatementHandle,SQLCHAR* StatementText,SQLINTEGER TextLength);
//SQLExecDirect直接执行SQL语句
SQLRETURN SQLFetch(SQLHSTMT StatementHandle); //SQLFetch移动光标 eg::while(SQL_NO_DATA!=SQLFetch(hSTMT)){}
SQLRETURN SQLGetData(SQLHSTMT StatementHandle,SQLUSMALLINT ColumNumber,SQLSMALLINT TargetType,SQLPOINTER TargetValueptr,SQLINTEGER Bufferlength,SQLINTEGER* StrLen_or_IndPtr);
//得到某列(ColumNumber)处的值
SQLRETURN SQLNumberResultCols(SQLHSTMT StatementHandle,SQLSMALLINT* ColumnCountPtr); //得到结果集中列数 ColumnCountPtr返回列数
SQLRETURN SQLDescribeCol(SQLHSTMT StatementHandle,SQLSMALLINT ColumnNumber,SQLCHAR* ColumnName,SQLSMALLINT Bufferlength,SQLSMALLINT* NamelengthPtr,SQLSMALLINT* DataTypePtr,SQLUINTEGER ColumnSizePtr,SQLSMALLINT* DecimalDigitsPtr,SQLSMALLINT* NullablePtr);
//得到结果集中列的描述
在数据库创建表(VS2015的平台下,通过可视化的窗口手动创建,)比如创建一个test的表,命令:
CREATE TABLE [dbo].[test] (
[oky] CHAR (8) NOT NULL,
[spoint] CHAR (10) NOT NULL,
[status] INT NULL,
[city] CHAR (10) NULL,
PRIMARY KEY CLUSTERED ([oky] ASC)
通过创建的表进行插入示例:(出入的数据key值不能相同,不然会发生插入错误)
#include <iostream>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>
using namespace std;
#define MAXBUFLEN 255
#define MaxNameLen 40
#define SQLBINDCOL
SQLHENV henv = SQL_NULL_HENV;//定义环境句柄
SQLHDBC hdbc1 = SQL_NULL_HDBC;//定义数据库连接句柄
SQLHSTMT hstmt1 = SQL_NULL_HSTMT;//定义语句句柄
int main()
{
RETCODE retcode;//错误返回码
retcode = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
if (retcode < 0)//错误处理
{
cout << "allocate errors." << endl;
return -1;
}
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);//大多数情况下要设置成3.0,否则有的函数不支持
if (retcode < 0) //错误处理
{
cout << "not 3.0 " << endl;
return -1;
}
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
if (retcode < 0) //错误处理
{
cout << "connection handle errors." << endl;
return -1;
}
char* szDSN = "sqlserver_0_151";
char* szUID = "sa";//log name
char* szAuthStr = "123123";//passward
SQLSetConnectAttr(hdbc1, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0);
retcode = SQLConnect(hdbc1, (SQLCHAR*)szDSN, (SWORD)strlen(szDSN), (SQLCHAR*)szUID, (SWORD)strlen(szUID), (SQLCHAR*)szAuthStr, (SWORD)strlen(szAuthStr));
if (retcode < 0) //错误处理
{
cout << "connect to ODBC datasource errors." << endl;
return -1;
}
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
if (retcode < 0) //错误处理
{
cout << "allocate ODBC statement handle errors." << endl;
return -1;
}
//建表(手动)
/*retcode = SQLExecDirect(hstmt1, (SQLCHAR*)"create table test(sky char(8) primary key,spoint char(10) not null,status int,city char(10))", SQL_NTS);
if (retcode < 0)
{
cout << "creat errors." << endl;
return -1;
}*/ //(代码建表)
retcode = SQLExecDirect(hstmt1, (SQLCHAR*)"insert into test values('SS0','港口','20','天津')", SQL_NTS);
if (retcode < 0)
{
cout << "ss0 insert errors." << endl;
return -1;
}
retcode = SQLExecDirect(hstmt1, (SQLCHAR*)"insert into test values('SS1','故宫','10','北京')", SQL_NTS);
if (retcode < 0)
{
cout << "ss1 insert errors." << endl;
return -1;
}
retcode = SQLExecDirect(hstmt1, (SQLCHAR*)"insert into test values('SS2','兵马俑','30','西安')", SQL_NTS);
if (retcode < 0)
{
cout << "ss2 insert errors." << endl;
return -1;
}
retcode = SQLExecDirect(hstmt1, (SQLCHAR*)"insert into test1 values('SS3','水','25',null)", SQL_NTS);
if (retcode < 0)
{
cout << "ss3 insert errors." << endl;
return -1;
}
retcode = SQLExecDirect(hstmt1, (SQLCHAR*)"SElECT spoint,city FROM test", SQL_NTS);
if (retcode < 0)
{
cout << "Executing errors." << endl;
return -1;
}
SQLCHAR city[MaxNameLen + 1];
SQLCHAR point[MaxNameLen + 1];
SQLINTEGER Len = 0;//列的长度
#ifdef SQLBINDCOL
retcode = SQLBindCol(hstmt1, 1, SQL_C_CHAR, point, MaxNameLen, &Len);
retcode = SQLBindCol(hstmt1, 2, SQL_C_CHAR, city, MaxNameLen, &Len);
while ((retcode = SQLFetch(hstmt1)) != SQL_NO_DATA)
{
if (columnLen > 0)
printf("point = %s city = %s\n", point, city);
else
printf("point = %s city = NULL\n", point, city);
}
#else
while (1)
{
retcode = SQLFetch(hstmt1);
if (retcode == SQL_NO_DATA)
break;
retcode = SQLGetData(hstmt1, 1, SQL_C_CHAR, point, MaxNameLen, &Len);
retcode = SQLGetData(hstmt1, 2, SQL_C_CHAR, city, MaxNameLen, &Len);
if (columnLen > 0)
printf("point = %s city = %s\n", point, city);
else
printf("point = %s city = NULL\n", point, city);
}
#endif
//释放
SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}