C操作MYSQL数据库

1 篇文章 0 订阅

简介

C语言下使用MySQL数据库提供的API操作数据库。建议结合查看API官方文档,开发环境搭建过程如下:
1. 安装MySQL数据库。(你的项目与MySQL Lib库位数必须一致,否则不兼容,比如你编写的程序是32位的就安装32位的MySQL数据库,64位就安装64位的MySQL数据库)如何安装这里就不介绍了,MySQL5.4版本后的都可以,对API没影响。
2. 在MySQL安装路径下找到lib文件中的libmysql.lib、libmysql.dll,复制到项目路径下,然后同样把MySQL安装路径下的include文件中的mysql.h复制到项目路径下。在项目头文件中添加库与头文件:

#include "mysql.h"
#pragma comment(lib,"libmysql.lib")

然后就可以愉快的使用C操作数据库啦!主要内容如下:
1. 配置与连接数据库。
2. 写数据库
3. 读数据库

1.配置与连接数据库

	const char host[] = "localhost";						//数据库ip地址,这里是本地数据库。
	const char name[] = "root";								//数据库用户名。
	const char passwd[] = "123";							//数据库密码。
	const char db[] = "hgdb";								//数据库名。
	
	MYSQL m_sqlCon;											//全局变量,数据库的句柄。
	
	mysql_init(&m_sqlCon);									//初始化数据库。
	my_bool mybool = true;									//typedef char my_bool,其实就是数据库的bool类型
	mysql_options(&m_sqlCon, MYSQL_OPT_RECONNECT, &mybool);				//开启自动重连(注意自动重连也是要调用mysql_ping()函数才会重连的),mysql_options函数可以配置数据库各种参数,比如传输的包大小,开启多SQL语句执行,读写超时时间等,总之可以优化数据库。
	if (mysql_real_connect(&m_sqlCon, host, name, passwd, db, 3306, NULL, CLIENT_MULTI_STATEMENTS))			//连接数据库。3306是数据库端口号,CLIENT_MULTI_STATEMENTS为开启多SQL语句执行。
	else
	{
		switch(mysql_errno(&m_sqlCon))							//连接数据库失败,查看错误信息。这里只列出了三个错误信息。
		{
			case CR_CONNECTION_ERROR: break;  //Failed to connect to the MySQL server.
			case CR_UNKNOWN_HOST: break;  //Failed to find the IP address for the host name.
			case CR_VERSION_ERROR: break; //A protocol mismatch resulted from attempting to connect to a server with a client library that uses a different protocol version.
			default: break;
		}
	}

要说明的都在注释中了。MySQL API提供了两种方式操作数据库,一种是mysql_real_query()函数执行SQL语句,另外一种就是prepared statement方式了。第一种方式使用起来很简单,就是把字符串类型SQL语句作为参数调用mysql_real_query()函数执行就行了。prepared statement方式对于频繁操作数据库有优势,具体使用哪种根据实际效率看吧。以下操作都会介绍两种方式。

2.写数据库

第一种方式:

string sql = "insert into `tableName` values(1, '2', ...)";						//就是简单的SQL语句而已,但是这里有两点要注意!表名两边加上`符号(Tab键上面的那个键也就是1键左边的键),字段值是字符或字符串类型的话两边要加'符号。
if(mysql_real_query(&m_sqlCon, sql.c_str(), sql.length())!=0)				//执行SQL语句,一个函数就实现了各种操作。执行成功返回0。
{
	unsigned int errCode = mysql_errno(&m_sqlCon);						//查看错误信息
	if(errCode==2014)
	{
		//Commands were executed in an improper order.
	}
	else if(errCode==2006)
	{
		//The MySQL server has gone away.;
	}
	else if(errCode==2013) 
	{
		//The connection to the server was lost during the query.;
	}
	else if(errCode==2000) 
	{
		//An unknown error occurred.;
	}
	mysql_ping(&m_sqlCon);				//检查数据库是否断开,如果断开就重连并且执行上一条出错的SQL语句。
}

第一种方式太简单了,直接调用mysql_real_query()执行各种SQL语句。但是要注意两点,SQL语句中表名两边加上`符号(Tab键上面的那个键也就是1键左边的键),字段值是字符或字符串类型的话两边要加’符号。
prepared statement方式
对于频繁执行的SQL语句,绑定到MYSQL_STMT类型变量中,类似预编译一样,其中原理查看API文档说明吧。首先调用mysql_stmt_init()函数申请MYSQL_STMT类型变量,然后调用mysql_stmt_prepare()函数绑定SQL语句,需要带值的SQL语句比如insert操作还需要调用mysql_stmt_bind_param()函数绑定值。字段值信息由MYSQL_BIND结构体存储。过程如下:

MYSQL_STMT *pstmt = mysql_stmt_init(&m_sqlCon);				//全局变量。使用完后记得调用mysql_stmt_close()释放!
string stmtSql = "insert into `tableName` values(?,?,?,?)";			//SQL语句。
mysql_stmt_prepare(pstmt, stmtSql.c_str(), stmtSql.length());		//绑定SQL语句到MYSQL_STMT变量中,也就是之后再执行该SQL操作直接用MYSQL_STMT变量就行了,不用再重复写该SQL语句了。类似预编译一样。
MYSQL_BIND bindStmt[4];															//insert操作,要插入几个字段值数组就多大。这里4个字段值。MYSQL_BIND结构体存储字段的一些信息,比如值,是否为非负,非空等。
char filed1 = 'a';
int filed2 = 1;
float filed3 = 2.2;
char filed4[] = "123";
memset(bindStmt, 0, sizeof(bindStmt));										//初始化为0
bindStmt[0].buffer_type = MYSQL_TYPE_TINY;							//char字段类型。
bindStmt[0].buffer = &filed1;														//注意赋的是地址而不是值。
bindStmt[0].buffer_length = sizeof(filed1);									//buffer的字节个数
bindStmt[1].buffer_type = MYSQL_TYPE_LONG;						//int类型
bindStmt[1].buffer = &filed2;
bindStmt[1].buffer_length = sizeof(filed2);
bindStmt[2].buffer_type = MYSQL_TYPE_FLOAT;
bindStmt[2].buffer = &filed3;
bindStmt[2].buffer_length = sizeof(filed3);
bindStmt[3].buffer_type = MYSQL_TYPE_STRING;
bindStmt[3].buffer = filed4;
bindStmt[3].buffer_length = sizeof(filed4);
mysql_stmt_bind_param(pstmt,  bindStmt);									//绑定字段值到MYSQL_STMT中。
if(mysql_stmt_execute(pstmt) != 0)												//执行SQL操作。
{
	unsigned int errCode = mysql_errno(&m_sqlCon);					//查看错误信息。
	if(errCode==2014)
	{
		//Commands were executed in an improper order.
	}
	else if(errCode==2006)
	{
		//The MySQL server has gone away.
	}
	else if(errCode==2013) 
	{
		//The connection to the server was lost during the query.;
	}
	else if(errCode==2000) 
	{
		//An unknown error occurred.;
	}
	mysql_ping(&m_sqlCon);
}

调用mysql_stmt_init()申请的MYSQL_STMT变量用完后记得调用mysql_stmt_close()释放,不要用一次释放一次,应该等不需要再执行该SQL操作时再释放。有多少需要频繁操作的SQL语句就可以申请多少MYSQL_STMT变量。这种方式不能在一条语句中执行多SQL操作。MYSQL_BIND结构体主要用到的属性有:

struct MYSQL_BIND
{
	enum enum_field_types buffer_type;					//字段值类型,具体类型查看API文档。
	void *buffer;														//需要赋值的变量地址。
	unsigned long buffer_length;							//buffer指向变量的字节个数。
	unsigned long *length;										//指向实际字节个数。
	my_bool *is_null;												//是否为空。
	my_bool is_unsigned;										//是否为非负数。
	......
}

3.读数据库

第一种方式

string sql = "select * from `" + tableName + "`";					//SQL语句,读取表中所有数据。
mysql_real_query(&m_sqlCon, sql.c_str(), sql.length());				//执行SQL语句。
MYSQL_RES *sqlRes = mysql_store_result(&m_sqlCon);					//查询结果集。还可以使用mysql_use_result(&m_sqlCon);
if (sqlRes)
{
	MYSQL_ROW sqlRow;						//typedef char **MYSQL_ROW,就是个二维字符数组,所以读取的字段值都是字符串形式的。
	int colums = mysql_num_fields(sqlRes);			//列数
	while (sqlRow = mysql_fetch_row(sqlRes))		//每次取出一行数据。
	{
		for(int i=0; i<colums; i++)
		{
			 string value(sqlRow[i]);				//字段值。
		}
	}
	mysql_free_result(sqlRes);					//释放结果集。
}

常用的查询结果集是mysql_store_result(),可以调用mysql_num_rows()获取行数,并且可以调用mysql_data_seek()或mysql_row_seek()改变当前行,缺点是需要足够的内存。如果查询的数据量很大,建议使用mysql_use_result(),每次只查询一行数据,所以占用内存少,但是缺点是不能获取行数,并且必须读取完所有行。
prepared statement方式

MYSQL_STMT *stmt;
int num_fields;       //列数。
MYSQL_FIELD *fields;  	//列字段信息。
MYSQL_BIND *rs_bind;  //存储字段值信息。
int data1;					//存储字段值。
float data2;				//存储字段值。
char data3[20];			//存储字段值。

stmt = mysql_stmt_init(&m_sqlCon);
string sql = "select * from `" + tableName + "`";					//SQL语句,读取表中所有数据。
mysql_stmt_prepare(stmt, sql.c_str(), sql.length());				//绑定SQL语句。
mysql_stmt_execute(stmt) ;										//执行SQL语句。
num_fields = mysql_stmt_field_count(stmt);			//获取列数。
if (num_fields > 0)
{
    MYSQL_RES *rs_metadata = mysql_stmt_result_metadata(stmt);				//获取结果集。
    fields = mysql_fetch_fields(rs_metadata);							//获取所有字段信息。可以编写万能查询操作,类似反射。
    rs_bind = (MYSQL_BIND *) malloc(sizeof (MYSQL_BIND) * num_fields);		//根据字段值个数开辟MYSQL_BIND空间。
    memset(rs_bind, 0, sizeof (MYSQL_BIND) * num_fields);
    for (int i = 0; i < num_fields; ++i)										//根据字段信息设置MYSQL_BIND。
    {
      rs_bind[i].buffer_type = fields[i].type;								//字段类型。
      switch (fields[i].type)
      {
        case MYSQL_TYPE_LONG:													//整型。
          rs_bind[i].buffer = (char *) &(data1);								//字段值存储在data1中。
          rs_bind[i].buffer_length = sizeof (data1);
          break;
		case MYSQL_TYPE_FLOAT:								//单精度浮点型float。
		  rs_bind[i].buffer = (char *)&(data2);				//字段值存储在data2中。
		  rs_bind[i].buffer_length = sizeof (data2);
          break;
        case MYSQL_TYPE_CHAR:										//字符串。
		  rs_bind[i].buffer = data3;					//字段值存储在data3中。
		  rs_bind[i].buffer_length = sizeof (data3);
          break;
        default:
          break;
      }
    }
	mysql_stmt_bind_result(stmt, rs_bind);				//绑定MYSQL_BIND。
    while (mysql_stmt_fetch(stmt))						//每次获取一行。
    {
     	//data1,data2,data3存储了字段值。
    }
    mysql_free_result(rs_metadata);					//释放结果集。
    free(rs_bind);								//释放MYSQL_BIND空间。
  }

结语

除了使用API操作MYSQL外,还可以使用MYSQL Connector/C,具体信息就去看MYSQL官方文档吧。

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值