C++的一个Sql操作类(仿C# 支持参数化)

Sql操作类的作用


        想必不少人在用C++编写操作数据库的程序时,就已经发现光是初始化的步骤就很繁琐,后续进行数据库增删改查的各种操作时,代码量更是急速上升。对于这种情况,比较好的解决方法就是自己定义一个类,从而显著的减少代码量,并且开发的时候更不容易出现错误,增强程序的可读性。


Sql操作类代码


以下是CSqlHelper类的代码:


File:stdafx.h

首先,我们要在这个预编译头文件中加入一行#import预编译指令

#import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF","adoEOF")


File:SqlHelper.h

在工程中新建头文件,输入以下代码

#pragma once
#include "stdafx.h"

class CSqlHelper
{
public:
	CSqlHelper(void);
	~CSqlHelper(void);
private:
	_ConnectionPtr m_pConn;
public:
	static CSqlHelper* pInst;
	static BOOL InitSqlServer();
	int ExecuteNonQuery(LPCTSTR sql,_ParameterPtr* arrPara,int nPara);
	_variant_t ExecuteScalar(LPCTSTR sql,_ParameterPtr* arrPara,int nPara);
	_RecordsetPtr GetDataReader(LPCTSTR sql,_ParameterPtr* arrPara,int nPara);
	_RecordsetPtr GetDataSet(LPCTSTR sql);
	void SetParameter(_ParameterPtr* arrPara,_variant_t var,DataTypeEnum dt,_int64 size);
};



File:SqlHelper.cpp

在工程中新建源文件,输入以下代码

#include "stdafx.h"
#include "SqlHelper.h"

CSqlHelper* CSqlHelper::pInst=NULL;

CSqlHelper::CSqlHelper(void)
{
}


CSqlHelper::~CSqlHelper(void)
{
}

BOOL CSqlHelper::InitSqlServer()
{
	CoInitialize(NULL);
	CSqlHelper* sql=new CSqlHelper();
	HRESULT hr;
	hr=sql->m_pConn.CreateInstance(__uuidof(Connection));
	if(FAILED(hr))
	{
		return false;
	}
	try
	{
		string connstr="Driver={sql server};server=";
		connstr+="127.0.0.1";
		connstr+=",";
		connstr+="1433";
		connstr+=";uid=";
		connstr+="xxx"; //登录名
		connstr+=";pwd=";
		connstr+="xxxxxxx"; //密码
		connstr+=";database=";
		connstr+="xxxxxx"; //数据库名
		sql->m_pConn->Open((_bstr_t)connstr.c_str(),"","",adModeUnknown);
	}
	catch(_com_error &e)
	{
		//失败
		return false;
	}
	CSqlHelper::pInst=sql;
	return true;
}

//非查询模式 用于SQL操作
int CSqlHelper::ExecuteNonQuery(LPCTSTR sql,_ParameterPtr* arrPara,int nPara)
{
	try
	{
		_CommandPtr pCommand=NULL;
		_RecordsetPtr pRst=NULL;
		pCommand.CreateInstance(_uuidof(Command));
		pCommand->ActiveConnection=m_pConn;
		pCommand->CommandText=sql;
		_variant_t vRecordsAffected;
		if(arrPara!=NULL)
		{
			for(int i=0;i<nPara;i++)
			{
				pCommand->Parameters->Append(arrPara[i]);
			}
		}
		pRst=pCommand->Execute(&vRecordsAffected,NULL,adCmdText);
		if(pRst->GetState()==adStateOpen)
		{
			pRst->Close();
			pRst.Release();
		}
		pCommand.Release();
		return vRecordsAffected.intVal;
	}
	catch(_com_error &e)
	{
		return 0;
	}
}

//获取第一行第一列SQL查询结果
_variant_t CSqlHelper::ExecuteScalar(LPCTSTR sql,_ParameterPtr* arrPara,int nPara)
{
	_variant_t var;
	_CommandPtr pCommand=NULL;
	_RecordsetPtr pRst=NULL;
	pCommand.CreateInstance(_uuidof(Command));
	pCommand->ActiveConnection=m_pConn;
	pCommand->CommandText=sql;
	if(arrPara!=NULL)
	{
		for(int i=0;i<nPara;i++)
		{
			pCommand->Parameters->Append(arrPara[i]);
		}
	}
	pRst=pCommand->Execute(NULL,NULL,adCmdText);
	pCommand.Release();
	if(pRst->GetState()!=adStateOpen) //未成功打开
	{
		return NULL;
	}
	if(pRst->adoEOF) //空记录
	{
		pRst->Close();
		pRst.Release();
		return NULL;
	}
	var=pRst->GetCollect(_variant_t((long)0));
	pRst->Close();
	pRst.Release();
	return var;
}

//获取数据集(无参数 静态游标)
_RecordsetPtr CSqlHelper::GetDataSet(LPCTSTR sql)
{
	_RecordsetPtr pRst=NULL;
	pRst.CreateInstance("ADODB.Recordset");
	pRst->Open(_variant_t(sql),m_pConn.GetInterfacePtr(),adOpenStatic,adLockOptimistic,adCmdText);
	if(pRst->GetState()!=adStateOpen) //未成功打开
	{
		return NULL;
	}
	if(pRst->adoEOF) //空记录
	{
		pRst->Close();
		pRst.Release();
		return NULL;
	}
	return pRst;
}

//获取DataReader
//获取的数据集为动态游标 可以传入参数
_RecordsetPtr CSqlHelper::GetDataReader(LPCTSTR sql,_ParameterPtr* arrPara,int nPara)
{
	_CommandPtr pCommand=NULL;
	_RecordsetPtr pRst=NULL;
	pCommand.CreateInstance(_uuidof(Command));
	pCommand->ActiveConnection=m_pConn;
	pCommand->CommandText=sql;
	if(arrPara!=NULL)
	{
		for(int i=0;i<nPara;i++)
		{
			pCommand->Parameters->Append(arrPara[i]);
		}
	}
	
	pRst=pCommand->Execute(NULL,NULL,adCmdText);
	pCommand.Release();
	if(pRst->GetState()!=adStateOpen) //未成功打开
	{
		return NULL;
	}
	if(pRst->adoEOF) //空记录
	{
		pRst->Close();
		pRst.Release();
		return NULL;
	}
	return pRst;
}

//初始化SQL参数
void CSqlHelper::SetParameter(_ParameterPtr* arrPara,_variant_t var,DataTypeEnum dt,_int64 size)
{
	arrPara[0].CreateInstance(__uuidof(Parameter));
	arrPara[0]->PutValue(var);
	arrPara[0]->PutDirection(adParamInput);
	arrPara[0]->PutType(dt);
	arrPara[0]->PutSize(size);
}


注:上述代码按照C#的SqlHelper使用习惯编写,对于使用过C#的朋友来说,这些应该会感到非常亲切。


Sql操作类的使用方法


初始化操作

        在我们执行任何的SQL之前,必须进行如下代码的初始化操作,否则ADO不能正常使用。

BOOL ret = CSqlHelper::InitSqlServer();

注:该函数返回值类型为BOOL型,表示是否成功的初始化了ADO以及数据库链接。为TRUE表示初始化成功,否则表示初始化失败。


获取CSqlHelper对象指针

        在完成初始化操作后,将得到一个CSqlHelper的对象指针,该指针就在CSqlHelper类的静态变量pInst中。

CSqlHelper* pHelper=CSqlHelper::pInst;


执行SQL命令(非查询模式)

        在我们要执行删表、删记录、插入记录、新建表等操作时,我们可以选择CSqlHelper类的ExecuteNonQuery方法。

pHelper->ExecuteNonQuery("你的SQL语句",NULL,0);


获取SQL查询的第一行第一列数据

        如果我们只需要SQL查询结果的第一行第一列这一个数据,我们可以使用ExecutreNonQuery方法,它的返回值类型为_variant_t型SQL变量。

pHelper->ExecuteScalar("你的SQL语句",NULL,0);


获取SQL查询的数据集(动态游标)

        如果我们想要获取一个动态的数据集,可以使用GetDataReader方法,该方法的返回值类型为_RecordsetPtr数据集类型。

pHelper->GetDataReader("你的SQL语句",NULL,0);


获取SQL查询的数据集(静态游标)

        如果我们要一个 静态的数据集,可以考虑使用GetDataSet方法,这个方法唯一的缺点就是不能进行参数化查询,该方法的返回值类型为_RecordsetPtr数据集类型。

pHelper->GetDataSet("你的SQL语句");


参数化查询


        有时候,在进行SQL操作时,如果SQL操作中的可变参数过多,通过直接拼接SQL字符串的方法过于不方便,甚至会存在安全问题(SQL注入漏洞),即使参数比较少,可以对传入的SQL参数进行转义或非法字符过滤,也不能保证在绝对意义上的安全。为了解决诸如此类的问题,SQL参数化查询是一个非常好的选择。


SQL参数数组的创建

        进行参数化查询的第一步就是创建SQL参数数组,以便后续通过SQL帮助类的类方法执行参数化SQL查询操作。下面是一个例子:

_ParameterPtr* para=new _ParameterPtr[2];
pHelper->SetParameter(para,_variant_t(str.c_str()),adVarChar,str.length()); //生成字符串参数
pHelper->SetParameter(para+1,_variant_t(nt),adInteger,sizeof(int)); //生成整形参数

        其中,在SetParameter函数中,第一个参数需要传入_ParameterPtr指针即为要初始化的那个参数对象,第二个参数传入_variant_t结构体格式的SQL变量,第三个参数传入参数的类型,第四个参数传入参数的大小。


SQL参数化查询的方法

        创建好了SQL参数数组之后,我们就可以进行参数化查询了,下面给出一个实例:

_ParameterPtr* para=new _ParameterPtr[1];
pHelper->SetParameter(para,_variant_t(str.c_str()),adVarChar,str.length()); //生成字符串参数
_variant_t vret=pHelper->ExecuteScalar("SELECT pwd FROM users WHERE usn=?",para,1);
delete[] para;

注:SQL语句中的参数位置请用"?"替换


        至此就是关于C++版仿C#的SQL SERVER数据库操作类的所有内容了,不知道各位看官有木有get到这个呢?

版权所有:《mntm博客》 => 《C++的一个Sql操作类(仿C# 支持参数化)
本文地址:http://www.mntm520.com/post/18
除非注明,文章均为 《mntm博客》 原创,欢迎转载!转载请注明本文地址,谢谢。

暧昧贴

发表评论

    微笑 大笑 拽 大哭 奸笑 流汗 喷血 生气 囧 不爽 晕 示爱 卖萌 吃惊 迷离 爱你 吓死了 呵呵

      已有1条评论

    1. avatar 阔乐沙发
      对新手学习数据库比较友好2018-10-17 00:40 回复