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 条评论