c/c++连接mysql数据库

        由于项目需要,要用c/c++链接mysql数据库。网上很多类似的解说,但是大部分都需要在本机器上安装完整版的msyql。其实,有时候我们并不想在改变自己电脑上原有的环境,但是我们却希望通过我们的程序链接数据库。比如:我在本机上已经安装了一个mysql,但并不是完整版的(比如appserv集成mysql或者wamp集成mysql),或者我的工作在局域网中,我只需要链接另外一台机器上的mysql。这样,为链接mysql而从头安装mysql server并不是一个最佳的选择。

        mysql官网中提供了connector能够满足我们的需求。截止到目前,connector的种类有:ODBC、NET、J、Python、C++、C、PHP。由于C++包含了C,而对于我而言更习惯C的链接方式,所以,本人采用了Connector/C。官网的下载地址为:http://dev.mysql.com/downloads/connector/,但是下载需要注册,我早就忘了oracle的账号了,后来又重新注册了一下。为防止一些人遇到与我一样的问题,我上传了一些Connector for c/c++,以供大家下载使用。下载网址为:点击打开链接

        将下载的mysql-connector-c-6.1.2-win32.zip解压,重命名目录名为mysql,并将mysql文件夹剪切至vs工作目录中。本人的vs版本为2008。

        有两种方式连接mysql数据库

        1、动态链接:添加mysql的include目录(项目工作目录/mysql/include)到工程(右击 - 属性- 配置属性 - C/C++ - 常规- 附加包含目录),然后添加mysql的lib目录(项目工作目录/mysql/lib)到工程(右击 - 属性- 配置属性 - 连接器- 常规-附加包含目录)。这种方式为动态链接,在编译后的exe文件运行时,需要把libmysql.dll文件拷贝到exe文件的同目录中,这用起来比较麻烦。

        2、如何把所有的代码都打包在一个exe中呢?那么就是静态连接。我们还可以在链接的时候用mysqlclient.lib库。具体为:首先然后改成release模式(因为mysqlclient.lib是在release模式下编译出来的),然后添加mysql的include目录(项目工作目录/mysql/include)到工程(右击 - 属性- 配置属性 - C/C++ - 常规- 附加包含目录),最后添加mysql的lib下对应的vc版本目录到工程而不是lib目录。比如:我用的是vs2008,其内部版本号为vs9,那么我将项目工作目录/mysql/lib/vs9目录添加到工程中(右击 - 属性- 配置属性 - 连接器- 常规-附加包含目录)。vs的版本号与年份的对应关系如下图所示。


          一个示例代码如下:

#include "mysql.h"
#include <stdio.h>

#pragma comment(lib, "mysqlclient.lib") 
#pragma comment(linker,"/nodefaultlib:LIBCMT.lib")  
#pragma comment(linker,"/nodefaultlib:MSVCRTD.lib")  
int main(int argc,char **argv)
{
	MYSQL* mysql = NULL;
	mysql = mysql_init(mysql);

	MYSQL_RES* res;
	MYSQL_ROW record;

	mysql_real_connect(mysql, "localhost", "root","123456", "kangry", 3306, NULL, NULL);
	mysql_query(mysql, "select * from whu_user;");
	res = mysql_store_result(mysql);
	while((record=mysql_fetch_row(res)))
	{
		printf("user_id=%s,user_name=%s,user_password=%s\n", record[0], record[1], record[2]);
	}
	mysql_free_result(res);
	mysql_close(mysql);
	
	getchar();

	return 0;	
}

其中代码第四行是链接lib文件,第5、6行必须加上,表示忽略LIBCMT.lib和MSVCRTD.lib库。否则会报类似如下错误:


error LNK2005: __configthreadlocale 已经在 MSVCRT.lib(MSVCR90.dll) 中定义


        若最开始未调成release模式,那么在添加mysql的lib时需要将工作目录/mysql/lib/vs9/debug目录添加到工程,并将项目的运行时库改成MT(多线程),具体为:项目邮件-》属性-》配置属性-》C/C++-》代码生成-》运行时库。否则,可能会报如下错误:warning LNK4217: 本地定义的符号 _printf 在函数 _main 中导入。

        另外,我还编了一个c/c++链接mysql的数据库类,这里贴出源代码,供大家和我以后参考。

common.h

#ifndef __COMMON_H
#define __COMMON_H

/************************************************************************/
/* 以下是系统的配置定义                                                 */
/************************************************************************/
#define USE_WINDOWS 1
#define CHARSETTYPE "utf8"

/************************************************************************/
/* 以下是数据库定义                                                     */
/************************************************************************/
#define DATABASE_SERVER	"localhost"
#define DATABASE_USER	"root"
#define DATABASE_PASS	"123456"
#define DATABASE_NAME	"test"

#endif

 mydb.h

#ifndef __MY_DB_H
#define __MY_DB_H
#include <mysql.h>  
#include <stdlib.h>  
#include <stdio.h>  
#include <iostream>  
#include <string>  
#include <map>
#include "common.h"

#if USE_WINDOWS
	#pragma comment(lib, "mysqlclient.lib") 
	#pragma comment(linker,"/nodefaultlib:LIBCMT.lib")  //忽略LIBCMT.lib库
	#pragma comment(linker,"/nodefaultlib:MSVCRTD.lib")  //忽略MSVCRTD.lib库
#endif

using namespace std; 

struct RECORD{
	int length;
	char ** data;
};

class CMyDB  
{  
public:  
	CMyDB();  
	bool initDB(const string& server_host , const string& user, const string& password, const string& db_name);  
	void closeDB();
	bool executeSQL(const string& sql_str, bool store_result=true);  
	void clearDB(const string& sql_str);
	void clearDB();
	bool truncateTable(const string& tableName); 
	const char* getLastError();
	RECORD getNextRecord(const string& sql_str);
	~CMyDB();  

private:  
	MYSQL *connection; 
	map<string,MYSQL_RES*> m_res;
	RECORD record;
};  
#endif

mydb.cpp

#include "mydb.h"

CMyDB::CMyDB()
{	
	//初始化连接数据库变量
	connection = mysql_init(NULL);
	if(connection == NULL)
	{
		perror("mysql_init");
		exit(1);
	}
}

CMyDB::~CMyDB()
{
	closeDB();
}

//初始化数据库 数据库连接
bool CMyDB::initDB(const string& server_host , const string& user, const string& password , const string& db_name )
{	
	//运用mysql_real_connect函数实现数据库的连接
	connection = mysql_real_connect(connection , server_host.c_str() , user.c_str() , password.c_str() , db_name.c_str() , 0 , NULL , 0);
	if(connection == NULL)
	{
		perror("mysql_real_connect");
		exit(1);
	}
	//设置编码
	if(mysql_query(connection, "set names " CHARSETTYPE))
	{
		fprintf(stderr, "%d: %s\n",mysql_errno(connection), mysql_error(connection));
		exit(1);
	}
	return true;
}

//关闭数据库连接
void CMyDB::closeDB()
{
	//关闭初始化连接数据库变量
	clearDB();
	if(connection != NULL){
		mysql_close(connection);
		connection=NULL;
	}
}

void CMyDB::clearDB(const string& sql_str){
	if (m_res[sql_str])
	{
		mysql_free_result(m_res[sql_str]);
		m_res.erase(sql_str);
	}
}

void CMyDB::clearDB(){
	for (map<string,MYSQL_RES*>::iterator iter=m_res.begin();iter!=m_res.end();iter++)
	{
		mysql_free_result(iter->second);
	}
	m_res.clear();
}

//执行SQL语句
bool CMyDB::executeSQL(const string& sql_str,bool store_result/*=true*/)
{
	int t = mysql_query(connection,  sql_str.c_str());
	if(t){
		printf("Error making query: %s\n" , mysql_error(connection));
		exit(1);
	}else if(store_result){
		if (m_res[sql_str]){
			mysql_free_result(m_res[sql_str]);
		}
		//初始化逐行的结果集检索
		m_res[sql_str] = mysql_store_result(connection);
	}
	return true;
}


//获得下一行的数据
RECORD CMyDB::getNextRecord(const string& sql_str){
	record.data=mysql_fetch_row(m_res[sql_str]);
	record.length=mysql_num_fields(m_res[sql_str]);
	return record;
}

//表的清空
bool CMyDB::truncateTable(const string& tableName)
{
	string sql="truncate table ";
	sql+=tableName;
	if(mysql_query(connection , sql.c_str()))
	{
		printf("Error making query: %s\n" , mysql_error(connection));
		exit(1);
	}
	return true;
}

//获得最近的错误
const char* CMyDB::getLastError(){
	return mysql_error(connection);
}

main.cpp

#include "common.h"
#include "mydb.h"
#include <stdio.h>
#include <string.h>

using namespace std;

int main(int argc,char **argv)
{
	CMyDB mydb;
	mydb.initDB(DATABASE_SERVER,DATABASE_USER,DATABASE_PASS,DATABASE_NAME);
	
	string s_sql="select * from user limit 10";
	mydb.executeSQL(s_sql);
	RECORD record=mydb.getNextRecord(s_sql);
	while (record.data)
	{
		for (int i=0;i<record.length;i++)
		{
			printf("%s\t",record.data[i]);
		}
		printf("\n");
		record=mydb.getNextRecord(s_sql);
	}
	mydb.clearDB(s_sql);
	mydb.closeDB();
	return 0;	
}

       希望我的随笔能给大家带来帮助。


0 条评论

    发表评论

    电子邮件地址不会被公开。 必填项已用 * 标注