最近需要在win32系统下用C++编译器测试MongoDb的性能,所以花了近一周的时间对MongoDb进行了初步的研究。
这里对于MongoDb的优势和一些规则就不细说了,详见
MongoDB实战中文版.pdf
MongoDB权威指南.pdf
在http://www.mongodb.org下载了最新版的,但是发现没有win32下的C++驱动,不得已,继续查找资料。
终于找到了一个1.2.1的windows32版本:
http://downloads.mongodb.org/win32/mongodb-win32-i386-1.2.1.zip
其中含有
执行该文件即可启动mongodb服务程序。
解压文件内还包含了c++的头文件和库文件。
将他们放到以下目录:
D:\mongodb\include
D:\mongodb\lib
所以打算利用它们来写mongodb客户程序。
但是
首先需要有boost,因为mongodb-win32-i386-1.2.1.zip里提供的mongodb库文件
D:\mongodb\1.2.1\mongodb-win32-i386-1.2.1\lib\mongoclient.lib
是用vs2008 + boost_1_35_0编译出来的,懒得重新编译mongodb,因此也对应的使用vs2008 + boost_1_35_0编译环境即可使用这个mongoclient.lib,boost_1_35_0从boost官网下载即可。
编译boost分两步:
1.执行D:\1.2.1\boost\boost_1_35_0\tools\jam\build_dist.bat
2.将第一步生成的bjam.exe拷贝到D:\boost\boost_1_35_0,然后执行:
cd D:\boost\boost_1_35_0
bjam.exe link=static threading=multivariant=release runtime-link=static --without-python --toolset=msvc-9.0
其中各参数的含义如下:
--build-dir=<builddir> 编译的临时文件会放在builddir里(编译完就可以把它删除了)
--stagedir=<stagedir> 存放编译后库文件的路径,默认是stage
--build-type=complete 编译所有版本,不然只会编译一小部分版本
(相当于variant=release,threading=multi;link=shared|static;runtime-link=shared)
variant=debug|release 决定编译什么版本(Debug orRelease)
link=static|shared 决定使用静态库还是动态库
threading=single|multi 决定使用单线程还是多线程库
runtime-link=static|shared 决定是静态还是动态链接C/C++标准库
--with-<library> 只编译指定的库,如输入--with-regex就只编译regex库了
--show-libraries 显示需要编译的库名称
完成后即会生成很多lib库,比如libboost_program_options-vc90-mt-s-1_35.lib,把这些lib库文件(搜索lib关键字)全部拷贝到D:\mongodb\uselib目录(uselib目录是我自己建立的)。
为了重复利用,以及方便以后可能delphi等其他编译器的运用,决定将一些常用功能编译成dll。
首先利用vs2008建立win32工程DLL,并做下设置:
1.工具-->选项-->项目和解决方案-->VC++目录
加上对应的包含文件:
D:\boost\boost_1_35_0
D:\mongodb\include\mongo
加上对应的库文件:
D:\mongodb\uselib
D:\mongodb\lib
(注:本来用的是1.2.1版本,但是我的系统中发生了点问题,后来用了1.8.1版本,但是驱动的头文件和库文件都没变)
2.项目-->属性(Alt+F7)-->配置属性-->C/C++-->代码生成-->运行时库选为多线程(/MT),即是静态的,不要用DLL。(对应boost库中”-mt-s-“名称)。
3. 项目-->属性(Alt+F7)-->配置管理器-->活动方案为release。(如果是debug会报错找不到-mt-sgd-)。
编译代码如下
// MongoDb.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#include <iostream>
#include "client/dbclient.h"
#pragma comment(lib, "mongoclient.lib")
#pragma comment(lib, "wsock32.lib")
using namespace std;
string errmsg;
string table = "hsds.logs";
mongo::DBClientConnection conn;
bool IfOpened = false;
void Ltrim(char *sStr)
{
unsigned int i;
if (strlen(sStr) <= 0) return;
for (i = 0; i < strlen(sStr); i++)
if (sStr[i] != ' ')
break;
strcpy(sStr, sStr + i);
return;
}
void Rtrim(char *sStr)
{
int i;
if (strlen(sStr) <= 0) return;
for (i = strlen(sStr) - 1; i >= 0; i--)
if (sStr[i] != ' ')
break;
sStr[i + 1] = '\0';
return;
}
void AllTrim(char *sStr)//去掉前后空格
{
Ltrim(sStr);
Rtrim(sStr);
}
extern "C" __declspec(dllexport) int MongoDbOpen(const char * ipport)
{
if (!conn.connect(string(ipport), errmsg)) {
cout << errmsg << endl;
return -1;
}
IfOpened = true;
return 1;
}
extern "C" __declspec(dllexport) int MongoDbInsert(char *format,...)//("name << %s << age << %d << email << %s << address << %s","wangjm",24,"419443006@qq.com","sadfsf");
{
if(IfOpened)
{
va_list args;
va_start(args,format);
int pos = 0;
char colname[1000];
mongo::BSONObjBuilder query;
char *tmp = format;
while(*format != '\0' )
{
// string
if( (*format == '%')&&(*(format+1) == 's') )//%s
{
char* s = va_arg( args, char * );
query << colname << s;
format = format + 2;
}
// MongoDb中用''存入单个字符,会转换成aci2
// character
else if( (*format == '%')&&(*(format+1) == 'c') )//%c
{
char c = (char)va_arg( args, int );//在可变长参数中,应用的是"加宽"原则。也就是char类型被扩展成int
//printf("%c\n",c);
char str[2];
str[0] = c;
str[1] = '\0';
query << colname << str;
format = format + 2;
}
// integer
else if( (*format == '%')&&(*(format+1) == 'd') )//%d
{
int d = va_arg( args, int );
query << colname << d;
format = format + 2;
}
else if( (*format == '%')&&(*(format+1) == 'f') )//%f
{
double f = va_arg( args, double);//在可变长参数中,应用的是"加宽"原则。也就是float类型被扩展成double,但是为了保证数据的准确性,当位数不满足float要求时,填充进随机数,这里直接用double型
query << colname << f;
format = format + 2;
}
/*
else if( (*format == '%')&&(*(format+1) == 'l') )//%l
{
long f = va_arg( args, long);
query << colname << f;
format = format + 2;
}
*/
else if( (*format == '<') && (*(format+1) == '<'))
{
memset((void *)colname,'\0',sizeof colname);
strncpy(colname,tmp,pos);
AllTrim(colname);
pos = 0;
format = format + 2;
tmp = format;
}
else
{
pos++;
format++;
}
}
va_end( args );
conn.insert(table, query.obj());
}
return 0;
}
extern "C" __declspec(dllexport) int MongoDbSelect(char *format = "all",...)
{
if(IfOpened)
{
va_list args;
va_start(args,format);
int pos = 0;
char colname[1000];
mongo::BSONObjBuilder query;
char *tmp = format;
if(strcmp(format,"all") != 0)
{
while(*format != '\0' )
{
// string
if( (*format == '%')&&(*(format+1) == 's') )
{
char* s = va_arg( args, char * );
query << colname << s;
//query.append(colname,s);
format = format + 2;
}
// MongoDb中用''存入单个字符,会转换成aci2
// character
else if( (*format == '%')&&(*(format+1) == 'c') )//%c
{
char c = (char)va_arg( args, int );//在可变长参数中,应用的是"加宽"原则。也就是char类型被扩展成int
//printf("%c\n",c);
char str[2];
str[0] = c;
str[1] = '\0';
query << colname << str;
format = format + 2;
}
// integer
else if( (*format == '%')&&(*(format+1) == 'd') )
{
int d = va_arg( args, int );
query << colname << d;
//query.append(colname,d);
format = format + 2;
}
else if( (*format == '%')&&(*(format+1) == 'f') )
{
double f = va_arg( args, double);//在可变长参数中,应用的是"加宽"原则。也就是float类型被扩展成double
query << colname << f;
//query.append(colname,f);
format = format + 2;
}
else if( (*format == '<') && (*(format+1) == '<'))
{
memset((void *)colname,'\0',sizeof colname);
//printf("%s\n",tmp);
strncpy(colname,tmp,pos);
AllTrim(colname);
pos = 0;
format = format + 2;
tmp = format;
}
else
{
pos++;
format++;
}
}
}
va_end( args );
auto_ptr<mongo::DBClientCursor> cursor = conn.query(table, query.obj());//C++的auto_ptr所做的事情,就是动态分配对象以及当对象不再需要时自动执行清理
while (cursor->more())
{
mongo::BSONObj obj = cursor->next();
cout << obj.jsonString() << endl;
}
}
return 0;
}
extern "C" __declspec(dllexport) int MongoDbRemove(char *format = "all",...)
{
if(IfOpened)
{
va_list args;
va_start(args,format);
int pos = 0;
char colname[1000];
mongo::BSONObjBuilder query;
char *tmp = format;
if(strcmp(format,"all") != 0)
{
while(*format != '\0' )
{
// string
if( (*format == '%')&&(*(format+1) == 's') )
{
char* s = va_arg( args, char * );
query << colname << s;
//query.append(colname,s);
format = format + 2;
}
// MongoDb中用''存入单个字符,会转换成aci2
// character
else if( (*format == '%')&&(*(format+1) == 'c') )//%c
{
char c = (char)va_arg( args, int );//在可变长参数中,应用的是"加宽"原则。也就是char类型被扩展成int
//printf("%c\n",c);
char str[2];
str[0] = c;
str[1] = '\0';
query << colname << str;
format = format + 2;
}
// integer
else if( (*format == '%')&&(*(format+1) == 'd') )
{
int d = va_arg( args, int );
query << colname << d;
//query.append(colname,d);
format = format + 2;
}
else if( (*format == '%')&&(*(format+1) == 'f') )
{
double f = va_arg( args, double);
query << colname << f;
//query.append(colname,f);
format = format + 2;
}
else if( (*format == '<') && (*(format+1) == '<'))
{
memset((void *)colname,'\0',sizeof colname);
//printf("%s\n",tmp);
strncpy(colname,tmp,pos);
AllTrim(colname);
pos = 0;
format = format + 2;
tmp = format;
}
else
{
pos++;
format++;
}
}
}
va_end( args );
conn.remove(table, query.obj());
}
return 0;
}
(记得提取函数生成头文件,以后调用dll如果不想自己重新预定义函数时,需要用到头文件)
编程成功后会生成
MongoDb.exp
MongoDb.lib
MongoDb.dll
会用到
MongoDb.h
最后在附一个调用生成dll的代码:
// test01.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include "MongoDb.h"
#pragma comment(lib, "MongoDb.lib")
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
MongoDbOpen("127.0.0.1:27017");
for(int i = 0 ; i < 10 ; i++)
{
MongoDbInsert("email << %d << address << %c",i,'a');
}
MongoDbSelect("email << %d",1);
cout<<"----------------------------"<<endl;
MongoDbRemove("email << %d",1);
MongoDbSelect();
cout<<"----------------------------"<<endl;
MongoDbRemove();
MongoDbSelect();
cout<<"----------------------------"<<endl;
getchar();
return 0;
}