C++控制台程序使用ODBC连接SQLServer
连接:
一、设置ODBC 的数据源
二、进行代码连接
总流程:
1、申请环境句柄
2、配置环境句柄
3、申请连接句柄
4、定义数据库名、用户名、用户密码
5、连接数据库,并验证是否连接成功
6、申请语句句柄
7、定义要执行的语句
8、执行语句
9、释放申请的句柄
1、申请环境句柄:
函数讲解:
SQLRETURN SQLAllocHandle(
SQLSMALLINT HandleType, // 输入变量类型
SQLHANDLE InputHandle, // 输入变量
SQLHANDLE * OutputHandlePtr); // 输出变量
HandleType:
SQL_HANDLE_ENV:用于申请环境句柄 SQLHENV
SQL_HANDLE_DBC :用于申请连接句柄 SQLHDBC
SQL_HANDLE_DESC:用于申请描述符句柄 SQLHDESC
SQL_HANDLE_STMT:用于申请语句句柄 SQLHSTMT
InputHandle:
该变量放入已经被分配好的前提句柄,如果第一个变量为环境句柄,则放入SQL_NULL_HANDLE即可,若果第一个变量为SQL_HANDLE_DBC,则第二个变量必须为已分配的环境句柄,如第一个变量为SQL_HANDLE_DESC,SQL_HANDLE_STMT则,第二个变量必须为已分配好的连接句柄。
OutputHandlePtr :
该变量为一个指针变量,用于保存申请来的句柄,申请句柄类型为第一个变量,在定义该指针的时候需注意类型一致。
返回值:
返回值有四种:SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR.
2、设置控制环境各个方面的特性。
SQLRETURN SQLSetEnvAttr(
SQLHENV EnvironmentHandle, // 环境句柄
SQLINTEGER Attribute, // 数据库连接池的属性
SQLPOINTER ValuePtr, // 和参数二对应的属性
SQLINTEGER StringLength); // 一个参数的长度
EnvironmentHandle:要进行配置的环境的句柄
Attribute:要进行配置的属性
ValuePtr:要与 属性 关联的值的指针。根据 属性 的值, 将 valueptr 将为32位整数值,或指向以 null 值结束的字符串。
图片来自( https://www.cnblogs.com/jadeshu/p/10663678.html)
二者更详细关系说明参考: https://docs.microsoft.com/zh-cn/sql/odbc/reference/syntax/sqlsetenvattr-function?view=sql-server-ver15
StringLength:将 valueptr 指向某个字符串或二进制缓冲区,则此参数应为 *将 valueptr 的长度。对于字符串数据,此参数应包含字符串中的字节数。
如果 将 valueptr 是一个整数,则将忽略 StringLength 。
返回值:
返回值有四种:SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
连接数据库:
SQLRETURN SQLConnect(
SQLHDBC ConnectionHandle, // 连接句柄
SQLCHAR * ServerName, // 数据库名
SQLSMALLINT NameLength1, // 数据库名长度
SQLCHAR * UserName, // 用户名
SQLSMALLINT NameLength2, // 用户名长度
SQLCHAR * Authentication, // 密码
SQLSMALLINT NameLength3); // 密码长度
返回值:
返回值有四种:SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
执行 sql 语句:
SQLRETURN SQLExecDirect(
SQLHSTMT StatementHandle, // 语句句柄
SQLCHAR * StatementText, // 要执行的语句
SQLINTEGER TextLength); // 语句长度
--------------------------------------------------------------------------------------------------------------------------------------------------
从结果集中提取下一个数据行集,并返回所有绑定列的数据。
SQLRETURN SQLFetch(
SQLHSTMT StatementHandle // 语句句柄
);
返回值:
SQL_SUCCESS、SQL_SUCCESS_WITH_INFO、SQL_NO_DATA、SQL_STILL_EXECUTING、SQL_ERROR 或 SQL_INVALID_HANDLE。
---------------------------------------------------------------------------------------------------------------------------------------------
检索结果集中单个列的数据,或在 SQLParamData 返回 SQL_PARAM_DATA_AVAILABLE 之后为单个参数检索数据。 可以多次调用此方法,以便在部分中检索可变长度数据。
SQLRETURN SQLGetData(
SQLHSTMT StatementHandle, // 语句句柄
SQLUSMALLINT Col_or_Param_Num, // 要检索列数据,它是要为其返回数据的列的编号。 结果集列按递增的列顺序编号,从1开始。
SQLSMALLINT TargetType, // 该列的数据类型
SQLPOINTER TargetValuePtr, // 指向要返回数据的缓冲区的指针。不能为 NULL
SQLLEN BufferLength, // 缓冲区的长度
SQLLEN * StrLen_or_IndPtr // 一个指针,指向要返回其长度或指示器值的缓冲区。 如果这是 null 指针,则不返回长度或指示器值。 当提取的数据为空时,这将返回错误。
);
返回值:
SQL_SUCCESS、SQL_SUCCESS_WITH_INFO、SQL_NO_DATA、SQL_STILL_EXECUTING、SQL_ERROR 或 SQL_INVALID_HANDLE。
---------------------------------------------------------------------------------------------------------------------------------------------
函数使用:
SQLHENV renv;
SQLHDBC rdbc;
SQLRETURN res;
res = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&renv) ; // 创建申请环境句柄
res = SQLSetEnvAttr(renv,SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER); //设置控制环境的各个属性
res = SQLAllocHandle(SQL_HANDLE_DBC,renv,&rdbc) // 创建申请连接句柄
//定义变量,存放数据库名,用户名和密码
SQLWCHAR db[] = '数据库名';
SQLWCHAR user[] = "用户名";
SQLWCHAR pwd[] = "密码";
// 进行数据库连接
res = SQLConnect(rdbc,db,SQL_NTS,user,SQL_NTS,pwd,SQL_NTS);
// 验证数据库是否连接成功
if(!(res == SQL_SUCCESS) || res == SQL_SUCCESS_WITH_INFO)
{
cout<<"数据库连接失败";
rerturn -1;
}
// 因为要进行数据可操作,使用数据库语句,申请语句句柄
SQLHSTMT rstmt;
res = SQLAllocHandle( SQL_HANDLE_STMT,rdbc,&rstmt) ; // 创建申请环境句柄
// 插入数据
SQLWCHAR sql1[] = L"insert into first.dbo.v1 (a,b,c,d,h,m) values ('a5','b5',28,25,24,'s')";
ret = SQLExecDirect(hstmt, sql1, SQL_NTS);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
std::cout << "插入成功!";
}
else
{
std::cout << ret << "\n";
std::cout << "插入失败!";
}
// 修改数据
SQLWCHAR sql3[] = L"update first.dbo.v1 set a='ak',b='bk',c=19,d=18 where a='aa'";
ret = SQLExecDirect(hstmt, sql3, SQL_NTS);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
std::cout << "修改成功!";
}
else
{
std::cout << ret << "\n";
std::cout << "修改失败!";
}
// 查询数据库表语句
SQLWCHAR sqlsel[] = "select * from first.dbo.v1";
// 执行语句
res = SQLExecDirect(rstmt,sqlsel,SQL_NTS);
// 遍历查到的数据库结果
if(res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO)
{
// 遍历
while(SQLFetch(rstmt) != SQL_NO_DATA)
{
// 获取每列中的数据
SQLCHAR str1[20],str2[20],str3[20],str4[20];
SQLINTEGER len_str1,len_str2,len_str3,len_str4;
SQLGetData(rstmt,1,SQL_C_CHAR,str1,40,&len_str1);
SQLGetData(rstmt,2,SQL_C_CHAR,str2,40,&len_str2);
SQLGetData(rstmt,3,SQL_C_CHAR,str3,40,&len_str3);
SQLGetData(rstmt,4,SQL_C_CHAR,str4,40,&len_str4);
}
}
// 注:如果在查询表数据之后执行插入或者删除操作(使用同一个句柄 rstmts),会导致失败。目前还未想通原因,有没有大佬知道,请指教!万分感谢!
// 释放连接的句柄
SQLFreeHandle(SQL_HANDLE_DBC,rdbc);
SQLFreeHandle(SQL_HANDLE_ENV,renv);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);//释放环境句柄
整体代码