分享
 
 
 

vc使用ADO操作数据库总结

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

一 关于初始化ADODB

需要在InitInstance()中首先调用AfxOleInit()对OLE进行初始化,之后要导入

c:\program files\common files\system\ado\msado15.dll,经过以上几步操作,接下来可以通过调用_ConnectionPtr和_RecordsetPtr来建立连接对象与记录集对象。为了简化编程,我封装了一个很简单的类库CDB,实现了对_ConnectionPtr的简单调用。

// DB.h: interface for the CDB class.

//

//////////////////////////////////////////////////////////////////////

#if !defined(__DB_H__)

#define __DB_H__

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF", "adoEOF") rename("LockTypeEnum", "adoLockTypeEnum") rename("DataTypeEnum", "adoDataTypeEnum")

#include "icrsint.h"

inline void TESTHR(HRESULT x) { if FAILED(x) _com_issue_error(x); }

inline BOOL IS_VT_NULL(unsigned short x) { return (x == VT_NULL ? TRUE : FALSE); }

class CDB

{

public:

CDB();

virtual ~CDB();

_RecordsetPtr Exec(CString& strSql);

void Close();

private:

_ConnectionPtr m_Conn;

};

class CSecUtil

{

public:

static CString StrReplace(LPTSTR lpszString, LPTSTR lpszKey, LPTSTR lpszReplace);

static BOOL StrCheck(LPCTSTR);

};

#endif // !defined(__DB_H__)

// DB.cpp: implementation of the CDB class.

//

//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "DB.h"

#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[]=__FILE__;

#define new DEBUG_NEW

#endif

//////////////////////////////////////////////////////////////////////

// CDB Construction/Destruction

//////////////////////////////////////////////////////////////////////

CDB::CDB()

{

try

{

m_Conn.CreateInstance(__uuidof(Connection));

// _bstr_t connstr = "driver={SQL Server};Server=127.0.0.1;DATABASE=;UID=;PWD="; // 针对mssql

_bstr_t connstr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=;user id=admin;jet oledb:database password="; // 针对ACCESS

}

catch(_com_error& e)

{

AfxMessageBox(e.Description());

}

}

CDB::~CDB()

{

if(m_Conn->State)

{

m_Conn->Close();

}

}

_RecordsetPtr CDB::Exec(CString& strSql)

{

_RecordsetPtr rs;

try

{

rs = m_Conn->Execute((_bstr_t)strSql, NULL, adCmdText);

}

catch(_com_error& e)

{

AfxMessageBox(e.Description());

}

return rs;

}

void CDB::Close()

{

if(m_Conn->State)

{

m_Conn->Close();

}

}

使用时先按需要填充connstr,之后可以使用

CDB db;

建立一个对象,调用db.Exec来执行sql语句,其内部通过调用连接对象的Execute()方法来实现,Exec()方法调用后返回一个_RecordsetPtr的对象。调用db.close()关闭数据库。

二 类型转换

成功执行一次SELECT操作后从数据库中取出的记录保存在由_RecordsetPtr所定义的记录集对象中,通过调用GetCollect方法,可以将记录取出,如:

CDB db;

_RecordsetPtr rs;

CString strSql;

strSql = "SELECT id, user FROM logon";

rs = db.Exec(strSql);

if(rs->EOF)

...

else

rs->GetCollect("id");

然而调用GetCollect()返回的类型为_variant_t(相关介绍见MSDN),需要将其转化成控件所支持得类型才能显示,当然这些数据的原始类型是由数据库字段的定义类型,可以通过判断结构中的vt这个变量来取出当前的数据类型。这个变量返回一个VARTYPE类型的值(见表1)。

以下列出的是针对ACCESS的字段类型的转换,MSSQL与ACCESS的字段类型相类似,大部分可以按照下面的方法对类型进行转换。

数字:rs->GetCollect("id").intVal;

BYTE:rs->GetCollect("id").bVal;

文本/备注/时间:(char*)(_bstr_t)(rs->GetCollect("user")

这里要注意,对于数字类型,需要判断有无符号的情况。下面是VARIANT结构对于数据类型的定义。注释后面的为VARTYPE枚举类型。对于特定类型的转换可以通过查表1来进行操作,对于VARTYPE类型的定型可以以VARENUM为关键字在MSDN中搜索(我使用的是MSDN 2003 April)。

LONGLONG llval; // VT_I8.

LONG lVal; // VT_I4.

BYTE bVal; // VT_UI1.

SHORT iVal; // VT_I2.

FLOAT fltVal; // VT_R4.

DOUBLE dblVal; // VT_R8.

VARIANT_BOOL boolVal; // VT_BOOL.

_VARIANT_BOOL bool;

SCODE scode; // VT_ERROR.

CY cyVal; // VT_CY.

DATE date; // VT_DATE.

BSTR bstrVal; // VT_BSTR.

IUnknown * punkVal; // VT_UNKNOWN.

IDispatch * pdispVal; // VT_DISPATCH.

SAFEARRAY * parray; // VT_ARRAY|*.

BYTE * pbVal; // VT_BYREF|VT_UI1.

SHORT * piVal; // VT_BYREF|VT_I2.

LONG * plVal; // VT_BYREF|VT_I4.

LONGLONG * pllVal; // VT_BYREF|VT_I8.

FLOAT * pfltVal; // VT_BYREF|VT_R4.

DOUBLE * pdblVal; // VT_BYREF|VT_R8.

VARIANT_BOOL * pboolVal; // VT_BYREF|VT_BOOL.

_VARIANT_BOOL * pbool;

SCODE * pscode; // VT_BYREF|VT_ERROR.

CY * pcyVal; // VT_BYREF|VT_CY.

DATE * pdate; // VT_BYREF|VT_DATE.

BSTR * pbstrVal; // VT_BYREF|VT_BSTR.

IUnknown ** ppunkVal; // VT_BYREF|VT_UNKNOWN.

IDispatch ** ppdispVal; // VT_BYREF|VT_DISPATCH.

SAFEARRAY ** pparray; // VT_ARRAY|*.

VARIANT * pvarVal; // VT_BYREF|VT_VARIANT.

PVOID * byref; // Generic ByRef.

CHAR cVal; // VT_I1.

USHORT uiVal; // VT_UI2.

ULONG ulVal; // VT_UI4.

ULONGLONG ullVal; // VT_UI8.

INT intVal; // VT_INT.

UINT uintVal; // VT_UINT.

DECIMAL * pdecVal // VT_BYREF|VT_DECIMAL.

CHAR * pcVal; // VT_BYREF|VT_I1.

USHORT * puiVal; // VT_BYREF|VT_UI2.

ULONG * pulVal; // VT_BYREF|VT_UI4.

ULONGLONG * pullVal; // VT_BYREF|VT_UI8.

INT * pintVal; // VT_BYREF|VT_INT.

UINT * puintVal; // VT_BYREF|VT_UINT.

(表1)

这里还有一个重要的值VT_NULL,它表示数据库中相应字段的数据为空。一些控件上无法处理VT_NULL的情况,例如:ListCtrl。如果使用ListCtrl对数据进行显示,可以考虑用下面的方法进行判断:

if(rs->GetCollect("user").vt == VT_NULL)

// record is null

else

// record is non-null

三 安全问题

现在流行SQL INJECTION,因此对于字符串的过滤是一个很重要的问题。

如果是用VB来做这样的程序,可以很容易的实现,VB中的字符串操作是很容易的,还可以使用VBSCRIPT中的正则表达式(VC中也可以使用VBSCRIPT中的正则表达式,然而方法我忘记了,记得Codeproject中有相关的文章。或者使用现成的库如BOOST,greta)。

如果不会正则表达式,也可以用下面的方法:

//

// 检查指定字符串中是否包含非法字符

//

BOOL StrCheck(LPCTSTR lpszString)

{

CString strKey = "\'\\\"%#|=+-)(@!`~:;],.?/"*&^$@!`~:;<>,.?/";

int len = strlen(lpszString);

for(int i = 0; i < len; i++)

{

for(int j = 0; j < strKey.GetLength(); j++)

{

if(lpszString[i] == strKey.GetAt(j)) return FALSE;

}

}

return TRUE;

}

如果程序的输入需要用到"'"或"""这两个符号的话,还应该进行相应的转换。

//

// 对于ACCESS和MSSQL

//

strUser.Replace("\'", "\'\'");

strUser.Replace("\"", "\"\"");

//

// 对于MySQL

//

strUser.Replace("\'", "\\\'");

strUser.Replace("\"", "\\\"");

对于使用搜索的话,还需要过滤掉"_"和"#",经过上面几步才能保证SQL INJECTION发生的几率减少。

对于多用户的系统,应该使用MD5的方法将登录的密码进行加密。

尽量不要使用ACCESS作为开发使用的数据库,其安全性实在是太差,即便是加了密码,也可以轻松在本地破解出来。推荐使用MySQL或者是MSSQL。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有