通常我们在用VC进行数据库编程时首先会考虑到用向导通过ADO控件操作.的确,这是一个非常方便的方法.但也存在很大的不足,编程上的一些限制暂且不提,在客户使用方面,如你把用ADO控件写成的程序移动到另一台机器,由于相应的控件可能并没有提前安装,还有路径等问题.使得使用起来极为不便,本文提供了一个封装好的ODBC类,很好地解决了这个问题,实现很灵活的编程.我通过自己创建的一个示例程序说明:
1. 我封装SQL的操作封装成一个类,用户使用时只要调用就行.
//tool.h
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>
#include <odbcinst.h>
#define SQLERR_FORMAT "SQL Error State:%s, Native Error Code: %lX, ODBC Error: %s"
#define MM_MAX_DB_ERRMSG_SIZE 1024
typedef struct tagHIS_ADMIN //示例程序所用结构
{
int iId;
char strName[64];
char strPwd[64];
char strRemark[256];
}HIS_ADMIN, *LPHIS_ADMIN;
BOOL InitSQLEnvironment(SQLHANDLE *pEnv);
BOOL CreateDBConnect(SQLHDBC *phDBC, SQLHANDLE dbEnv, const char* pOdbcName,
const char* pUserName, const char* pPwd, char *errmsg);
BOOL GetDBError(SQLCHAR *errmsg, SWORD fHandleType, SQLHANDLE handle);
BOOL CreateDBState(SQLHSTMT *phStMt, SQLHDBC hDBC, char *errmsg);
//tool.cpp
注意在头部包含此语句:
#pragma comment(lib, "odbc32.lib")
//初始化.
BOOL InitSQLEnvironment(SQLHANDLE *pEnv)
{
// Allocate an Environment Handle
if (SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, pEnv) != SQL_SUCCESS)
{
return FALSE;
}
SQLRETURN sRet = SQLSetEnvAttr(*pEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
if (sRet != SQL_SUCCESS)
{
SQLFreeHandle(SQL_HANDLE_ENV, *pEnv);
return FALSE;
}
return TRUE;
}
//创建数据库连接
BOOL CreateDBConnect(SQLHDBC *phDBC, SQLHANDLE dbEnv, const char* pOdbcName,
const char* pUserName, const char* pPwd, char *errmsg)
{
// Allocate ODBC connection handle and connect.
SQLRETURN sRet;
sRet = SQLAllocHandle(SQL_HANDLE_DBC, dbEnv, phDBC);
if((sRet != SQL_SUCCESS_WITH_INFO) && (sRet != SQL_SUCCESS))
{
GetDBError((SQLCHAR *)errmsg, SQL_HANDLE_DBC, NULL);
return FALSE;
}
sRet = SQLConnect(*phDBC, (UCHAR *)pOdbcName, SQL_NTS,
(UCHAR *)pUserName, SQL_NTS,
(UCHAR *)pPwd, SQL_NTS);
if((sRet != SQL_SUCCESS) && (sRet != SQL_SUCCESS_WITH_INFO))
{
GetDBError((SQLCHAR *)errmsg, SQL_HANDLE_DBC, *phDBC);
SQLFreeHandle(SQL_HANDLE_DBC, *phDBC);
*phDBC = SQL_NULL_HDBC;
return FALSE;
}
return TRUE;
}
//自定义错误函数
BOOL GetDBError(SQLCHAR *errmsg, SWORD fHandleType, SQLHANDLE handle)
{
UCHAR szErrState[SQL_SQLSTATE_SIZE + 1]; // SQL Error State string
UCHAR szErrText[SQL_MAX_MESSAGE_LENGTH + 1]; // SQL Error Text string
char szBuffer[SQL_SQLSTATE_SIZE + SQL_MAX_MESSAGE_LENGTH + 1];
// formatted Error text Buffer
SWORD wErrMsgLen; // Error message length
SQLINTEGER iErrCode; // Native Error code
int iSize; // Display Error Text size
SQLRETURN nErrResult; // Return Code from SQLGetDiagRec
SWORD sMsgNum = 1;
BOOL bRetVal = TRUE;
szBuffer[0] = '/0';
while((nErrResult = SQLGetDiagRec(fHandleType, handle, sMsgNum++, szErrState, &iErrCode, szErrText,
SQL_MAX_MESSAGE_LENGTH - 1, &wErrMsgLen)) != SQL_NO_DATA)
{
if(nErrResult == SQL_ERROR || nErrResult == SQL_INVALID_HANDLE)
{
break;
}
wsprintf(szBuffer, SQLERR_FORMAT, (LPSTR)szErrState, iErrCode, (LPSTR)szErrText);
if (strncmp((char *)szErrState, "08", 2) == 0 || strncmp((char *)szErrState, "01000", 5) == 0)
{
//数据库已经断开
bRetVal = FALSE;
}
iSize = strlen((char *)errmsg);
if (iSize && (iSize + strlen(szBuffer) + 1) >= MM_MAX_DB_ERRMSG_SIZE)
{
break;
}
if (iSize)
{
strcat((char *)errmsg, "/n");
}
strcat((char *)errmsg, szBuffer);
}
return bRetVal;
}
//执行函数
BOOL CreateDBState(SQLHSTMT *phStMt, SQLHDBC hDBC, char *errmsg)
{
// Allocate statement handle, then execute command.
SQLRETURN sRet;
sRet = SQLAllocHandle(SQL_HANDLE_STMT, hDBC, phStMt);
if((sRet != SQL_SUCCESS) && (sRet != SQL_SUCCESS_WITH_INFO))
{
GetDBError((SQLCHAR *)errmsg, SQL_HANDLE_STMT, NULL);
return FALSE;
}
return TRUE;
}
2.实际使用方法:
在His.cpp中
BOOL CHisApp::InitInstance()
{
///////////////////////begin///////////////////////////////////////
if (!InitSQLEnvironment(&m_hDBEnv))
{
AfxMessageBox("设置ODBC环境失败");
return FALSE;
}
char errmsg1[512];
BOOL bRetVal = TRUE;
memset(errmsg1, 0, sizeof(errmsg1));
// his_conn为数据源名,hisuser:用户名,888888:密码
bRetVal = CreateDBConnect(&m_hDBC, m_hDBEnv, "his_conn", "hisuser", "888888", errmsg1);
if(!bRetVal)
{
AfxMessageBox(errmsg1);
return FALSE;
}
bRetVal = CreateDBState(&m_hStMt, m_hDBC, errmsg1);
if(!bRetVal)
{
AfxMessageBox(errmsg1);
return FALSE;
}
///////////////////////end///////////////////////////////////////
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// Change the registry key under which our settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CHisDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CHisView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
3.具体使用举例:
BOOL CRightListView::ReadRecord(CArray<HIS_ADMIN *, HIS_ADMIN*> *ur)
{
SQLRETURN sRet;
char errmsg[MM_MAX_DB_ERRMSG_SIZE];
char szState[512];
long reason;
SQLINTEGER len[12];
char szAction[1024];
sprintf(szAction, "管理员查询");
sprintf(szState, "exec his..his_proc_get_admin");//已经创建好的存储过程
sRet = SQLExecDirect(theApp.m_hStMt, (SQLCHAR *)szState, SQL_NTS);
if (sRet != SQL_SUCCESS && sRet != SQL_SUCCESS_WITH_INFO)
{
AfxMessageBox("执行查询语句失败");
return FALSE;
}
else
{
SQLBindCol(theApp.m_hStMt, 1, SQL_C_LONG, &reason, 0, &len[0]);
SQLBindCol(theApp.m_hStMt, 2, SQL_C_CHAR, errmsg, MM_MAX_DB_ERRMSG_SIZE, &len[1]);
sRet = SQLFetch(theApp.m_hStMt);
if (sRet != SQL_SUCCESS && sRet != SQL_SUCCESS_WITH_INFO)
{
AfxMessageBox("没有结果");
return FALSE;
}
sRet = SQLMoreResults(theApp.m_hStMt);
if (sRet != SQL_SUCCESS && sRet != SQL_SUCCESS_WITH_INFO)
{
AfxMessageBox("failed");
return FALSE;
}
HIS_ADMIN dat;
HIS_ADMIN *pData;
SQLBindCol(theApp.m_hStMt, 1, SQL_C_LONG, &dat.iId, 0, &len[0]);
SQLBindCol(theApp.m_hStMt, 2, SQL_C_CHAR, &dat.strName, 64, &len[1]);
SQLBindCol(theApp.m_hStMt, 3, SQL_C_CHAR, &dat.strPwd, 64, &len[2]);
SQLBindCol(theApp.m_hStMt, 4, SQL_C_CHAR, &dat.strRemark, 255, &len[3]);
while(1)
{
memset(&dat, 0, sizeof(HIS_ADMIN));
sRet = SQLFetch(theApp.m_hStMt);
if (sRet != SQL_SUCCESS && sRet != SQL_SUCCESS_WITH_INFO)
{
break;
}
pData = (HIS_ADMIN *)calloc(1, sizeof(HIS_ADMIN));
VERIFY(pData);
memcpy(pData, &dat, sizeof(HIS_ADMIN));
ur->Add(pData); //save recordset
}
}
return TRUE;
}
分享到:
相关推荐
### Visual C++中的ODBC编程实例 #### 一、ODBC简介 开放数据库连接(ODBC)是一种标准的数据库访问接口,它允许程序通过统一的API(应用程序编程接口)访问不同的数据库管理系统(DBMS)。微软在早期就推出了针对...
总的来说,ODBC的MFC编程是一个涵盖数据库连接、查询、事务管理和高级操作的综合主题。通过实践压缩包中的四个示例,你可以逐步构建起对这一技术的理解,并能灵活运用到实际项目中。在学习过程中,不断练习和查阅...
通过以上内容的详细介绍,我们可以了解到VC++在数据库编程方面提供了多种强大的工具和技术支持,无论是对于初学者还是资深开发者而言,都是一个非常有价值的参考资源。通过对这些技术的学习和实践,开发者可以更好地...
ODBC是一个由微软开发的API(应用程序编程接口),它允许程序员编写一次代码,就可以在多种数据库上运行,而无需关心底层数据库的具体实现。ODBC驱动程序是连接应用程序与特定数据库的关键,它负责将ODBC调用转化为...
### ODBC编程入门知识点概述 #### 一、ODBC简介 ODBC(Open Database Connectivity)是一种开放数据库连接标准,由微软公司在1991年推出。它为应用程序提供了一个统一的接口来访问不同的数据库管理系统(DBMS),...
"Linux/Unix下ODBC的安装、配置与编程" 本文主要介绍了ODBC的简单原理,以及如何在Linux/Unix下进行ODBC的安装、配置与...ODBC在Linux/Unix下可以提供一个统一的数据库访问接口,使得数据库编程变得更加简单和灵活。
CDatabase类是ODBC编程的核心,它代表一个数据库连接。通过创建CDatabase对象并调用OpenEx()或Open()函数,可以建立与数据源的连接。连接参数可以在构造函数中指定,也可以在Open()函数中传递。一旦连接建立,就...
通过这种方式,你可以创建一个灵活的MFC对话框应用程序,允许用户输入ODBC连接信息,执行查询,并在对话框上显示结果。这种实现方式特别适用于那些需要在多个不同的开发环境中进行数据库访问的应用,因为对话框可以...
标题中的"MFC-ODBC.zip"指的是一个压缩文件,包含了关于如何在MFC应用中使用ODBC进行数据库操作的相关资料。这个压缩包很可能是包含源代码、教程文档或者示例项目,旨在帮助开发者学习和实践MFC与ODBC的结合使用。 ...
ODBC编程主要遵循以下步骤: ##### 1. 初始化环境 首先,需要创建一个环境句柄,这将用于后续的数据库连接和语句处理。这一步骤通常通过调用`SQLAllocHandle`或`SQLAllocEnv`函数实现。例如: ```cpp #include ...
3. 使用MFC AppWizard创建数据库应用:创建一个名为Ex_ODBC的单文档应用程序,启用数据库支持,选择ODBC数据源“Database Example For VC++”,并选择要使用的表“score”。 4. 设计浏览记录界面:MFC自动生成用于...
使用Open方法打开一个记录集,然后可以通过MoveFirst、MoveNext等方法遍历记录,或者使用AddNew、Update和Delete方法进行添加、修改和删除操作。 5. **处理错误**:在ODBC编程中,需要捕获并处理SQL状态码,以便...
CRecordset类是MFC ODBC编程的核心,它代表了一个记录集,通常是一组从数据库中检索的记录。CRecordset提供了多种功能,包括浏览、添加、编辑和删除记录。根据应用的需求,记录集可以是动态集或快照。 动态集...
Linux/Unix 下 ODBC 的安装、配置...ODBC 是一个统一的数据库访问标准,它可以使应用程序和数据库系统之间的交互更加简单和灵活。在 Linux/Unix 下进行 ODBC 的安装、配置与编程可以使我们的数据库编程更加简单和高效。
1. **配置ODBC数据源**:在Windows控制面板中找到“管理工具”>“ODBC数据源管理员”,在这里创建一个新的系统或用户DSN(数据源名称),选择Access驱动程序,并提供数据库文件的路径。 2. **引入MFC数据库类库**:...
MFC中的CDatabase、CRecordset和CFieldExchange类是ODBC编程的核心。`CDatabase`代表一个数据库连接,`CRecordset`用于处理查询结果,而`CFieldExchange`则处理字段数据的交换。 ### 2. 连接数据库 首先,你需要...
DSN,即数据源名称,是在ODBC数据源管理器中定义的一个配置项,其中包含了数据库驱动、服务器名、用户名、密码等连接信息,用于简化数据库连接过程。 ### 不创建DSN直接使用ODBC数据源的方法 #### 1. 直接在代码中...