由于项目需要,要用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
#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
#include
#include
#include
#include
#include
#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 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::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
#include
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
{
printf("%s\t",record.data[i]);
}
printf("\n");
record=mydb.getNextRecord(s_sql);
}
mydb.clearDB(s_sql);
mydb.closeDB();
return 0;
}
希望我的随笔能给大家带来帮助。