1. 简介
Microsoft SQL Server,通常简称为MSSQL,是一种关系型数据库管理系统。与其他数据库一样,MSSQL可以使用多种编程语言来操作,例如C语言。
2. 连接配置
2.1 下载SQL Server驱动
在使用C语言连接MSSQL之前,需要下载相应的驱动程序。其中,Microsoft官网提供的ODBC驱动较为常见。
官网下载地址:https://www.microsoft.com/zh-CN/download/details.aspx?id=36434
下载安装后,需要在电脑的ODBC数据源管理器中添加数据源,以下是具体步骤:
打开ODBC数据源管理器
在“用户数据源”或“系统数据源”中,点击“添加”
选择“ODBC驱动程序 for SQL Server”并选择“完成”
填写MSSQL的相关信息,例如MSSQL的IP地址、数据库名称、登录名、密码等
保存配置并测试连接是否成功
2.2 连接代码实现
连接MSSQL所需的头文件和库文件如下:
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#pragma comment(lib, "odbc32.lib")
#pragma comment(lib, "odbccp32.lib")
其中,sql.h
和sqlext.h
是提供ODBC支持的文件,Windows API中包含了这两个文件。
连接MSSQL数据库的代码如下(其中,部分易发生错误的代码以标记):
SQLHENV env;
SQLHDBC dbc;
SQLHSTMT stmt;
SQLRETURN ret;
char* connectString = "DSN=YOUR_DSN_NAME";
ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
fprintf(stderr, "Couldn't allocate handle.\n");
goto error;
}
ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
fprintf(stderr, "Couldn't set the environment attribute.\n");
goto error;
}
ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
fprintf(stderr, "Couldn't allocate handle.\n");
goto error;
}
// 连接MSSQL数据库
SQLCHAR* inConnection = (SQLCHAR*)connectString;
SQLSMALLINT inConnectionLength = SQL_NTS;
ret = SQLDriverConnect(dbc, NULL, inConnection, inConnectionLength, NULL, 0, NULL, SQL_DRIVER_COMPLETE_REQUIRED);
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
fprintf(stderr, "Couldn't connect to database.\n");
goto error;
}
// 获取数据库版本
SQLCHAR versionBuff[1024];
SQLSMALLINT length;
SQLINTEGER needLength;
SQLExecDirect(stmt, (SQLCHAR*)"SELECT @@version", SQL_NTS);
/* 如果被选择数据大于0行,那么将结果集中的数据绑定到变量中 */
SQLBindCol(stmt, 1, SQL_C_CHAR, versionBuff, sizeof(versionBuff), &length);
ret = SQLFetch(stmt);
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
fprintf(stderr, "Couldn't execute SQL statement.\n");
goto error;
}
printf("MSSQL version: %s\n", versionBuff);
SQLDisconnect(dbc);
error:
SQLFreeHandle(SQL_HANDLE_ENV, env);
代码含义:
首先定义所需的句柄和返回值
使用SQLAllocHandle函数为环境、连接和语句创建句柄
使用SQLSetEnvAttr函数设置ODBC版本为ODBC 3.x
使用SQLDriverConnect函数连接数据库,其中需要传入DSN参数
使用SQLExecDirect函数执行SQL语句
使用SQLBindCol将结果集中的数据绑定到变量中
使用SQLFetch函数获取结果集的一行数据
使用SQLDisconnect函数断开连接
使用SQLFreeHandle函数释放句柄
2.3 连接池
在应用程序需要高并发执行SQL语句时,连接池可以提高应用程序的性能和响应速度。连接池是通过缓存和重用数据库连接来实现的。
在C语言中使用连接池前,需要先构建连接池。连接池的构建通常遵循以下步骤:
初始化连接池中的所有连接
创建一个“已用连接”队列和一个“未用连接”队列
连接池在开始运行后,所有的连接都在“未用连接”队列中
当需要连接数据库时,应用程序从“未用连接”队列中取出一个连接,并将其移动到“已用连接”队列中
当使用结束后,应用程序将连接从“已用连接”队列中移动到“未用连接”队列中
下面是一个简单的连接池实现:
#define MAX_CONNECTION_POOL 20
SQLHDBC g_hDbc[MAX_CONNECTION_POOL] = {0};
BOOL g_bIsUsed[MAX_CONNECTION_POOL] = {0};
/* 连接MSSQL数据库 */
void InitPool()
{
// 创建驱动环境句柄
SQLHENV hEnv;
// 创建连接句柄
for (int i = 0; i < MAX_CONNECTION_POOL; i++)
{
SQLRETURN rc;
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);
rc = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
rc = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &g_hDbc[i]);
}
// 连接数据库
for (int i = 0; i < MAX_CONNECTION_POOL; i++)
{
char connectString[256];
snprintf(connectString, sizeof(connectString), "DSN=%s", "YOUR_DSN_NAME");
SQLCHAR* inConnection = (SQLCHAR*)connectString;
SQLSMALLINT inConnectionLength = SQL_NTS;
rc = SQLDriverConnect(g_hDbc[i], NULL, inConnection, inConnectionLength, NULL, 0, NULL, SQL_DRIVER_COMPLETE_REQUIRED);
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
fprintf(stderr, "couldn't connect to database : %d.", rc);
continue;
}
}
}
SQLHDBC GetConnectionFromPool()
{
int index = -1;
for (int i = 0; i < MAX_CONNECTION_POOL; i++)
{
if (g_bIsUsed[i] == false)
{
index = i;
break;
}
}
if (index == -1)
{
return NULL;
}
g_bIsUsed[index] = true;
return g_hDbc[index];
}
void PushConnectionToPool(SQLHDBC hDesc)
{
for (int i = 0; i < MAX_CONNECTION_POOL; i++)
{
if (g_hDbc[i] == hDesc)
{
g_bIsUsed[i] = false;
}
}
}
连接池实现的关键就是将所有的连接预先创建并缓存到一个数组中,并在需要连接数据库时从数组中取出一个未被占用的连接,并标记它被占用。使用结束后,再将连接标记为空闲。
3. 数据库操作
3.1 插入数据
插入一条数据的代码如下:
SQLCHAR sql[] = "USE YOUR_DATABASE_NAME INSERT INTO YOUR_TABLE_NAME(id, name) VALUES(1, 'test')";
SQLExecDirect(stmt, (SQLCHAR*)sql, SQL_NTS);
代码含义:
首先需要使用USE命令选择要使用的数据库
然后,使用INSERT INTO命令插入数据,其中YOUR_TABLE_NAME
需要替换成要插入数据的表名
使用SQLExecDirect函数执行SQL语句
3.2 查询数据
查询一条数据的代码如下:
SQLCHAR sql[256];
sprintf((char*)sql, "USE YOUR_DATABASE_NAME SELECT * FROM YOUR_TABLE_NAME WHERE id = %d", 1);
SQLExecDirect(stmt, (SQLCHAR*)sql, SQL_NTS);
SQLSMALLINT id;
SQLCHAR name[64];
SQLINTEGER nameLen;
/* 如果被选择数据大于0行,那么将结果集中的数据绑定到变量中 */
SQLBindCol(stmt, 1, SQL_C_SSHORT, &id, sizeof(id), NULL);
SQLBindCol(stmt, 2, SQL_C_CHAR, name, sizeof(name), &nameLen);
while(SQLFetch(stmt) != SQL_NO_DATA) {
printf("id=%d, name=%s\n", id, name);
}
代码含义:
首先需要使用USE命令选择要使用的数据库
然后,使用SELECT命令查询数据,其中YOUR_TABLE_NAME
需要替换成要查询数据的表名
使用SQLExecDirect函数执行SQL语句
使用SQLBindCol将结果集中的数据绑定到变量中
使用SQLFetch函数获取结果集的一行数据,并输出
3.3 更新数据
更新一条数据的代码如下:
SQLCHAR sql[256];
sprintf((char*)sql, "USE YOUR_DATABASE_NAME UPDATE YOUR_TABLE_NAME SET name = 'new_name' WHERE id = %d", 1);
SQLExecDirect(stmt, (SQLCHAR*)sql, SQL_NTS);
代码含义:
首先需要使用USE命令选择要使用的数据库
然后,使用UPDATE命令更新数据,其中YOUR_TABLE_NAME
需要替换成要更新数据的表名
使用SQLExecDirect函数执行SQL语句
3.4 删除数据
删除一条数据的代码如下:
SQLCHAR sql[256];
sprintf((char*)sql, "USE YOUR_DATABASE_NAME DELETE FROM YOUR_TABLE_NAME WHERE id = %d", 1);
SQLExecDirect(stmt, (SQLCHAR*)sql, SQL_NTS);
代码含义:
首先需要使用USE命令选择要使用的数据库
然后,使用DELETE FROM命令删除数据,其中YOUR_TABLE_NAME
需要替换成要删除数据的表名
使用SQLExecDirect函数执行SQL语句
4. 结论
本文介绍了如何使用C语言连接MSSQL数据库,包括连接配置、数据库操作等,还介绍了连接池的实现方法,希望对大家有所帮助。