数据库编程——案例开发

在学习数据库编程总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

09-数据库编程day06(案例开发)

目录:
一、学习目标
二、MongoDB复习
三、MongoDB API
0、复习API构造函数、连接函数、插入、删除
1、通过API修改数据和查询分析
2、通过API查询文档
3、通过API查询文档、内容解析、异常捕捉
四、案例开发(网盘-服务器端)
1、案例需求分析、模型设计
2、搭建框架
3、MySQL端登录实现
4、SQL注入问题解决
5、查看功能实现
6、MySQL侧实现上传功能
7、上传文件MongoDB侧实现
8、MySQL与MongoDB类的调用
9、上传测试成功
10、下载功能实现
11、总结

 

一、学习目标

1. api 实现查询功能.
2. 案例的数据模型设计
3. 了解案例实现的核心原理
4. 案例的程序框架搭建
5. 了解案例实现的过程

 

二、MongoDB复习

》体系结构:库—集合
集合:对应关系型数据库的表,键值对的组合
文档:键值对,json

》删库分2步:
○ 切库use dbname
○ 删库db.dropDatabase()

》文档的新增:
---insert
db.collection_name.insert(json)
--save 指定了_id时,相当于修改
--find
db.collection_name.find({cond},{show})

db.collection.aggregate() $group   group By col1,col2  —— _id:{col1,col2}
--按位置,年龄分组,计算人数
db.Barca.aggregate({ $group:{ _id:{pos:"$pos",age:"$age"},count:{$sum:1}  }   })

--update
db.collection_name.update({query},{update},{upsert:false,multi:false})
--remove
db.collection_name.remove({query},{justOne:false})

--index
db.collection_name.ensureIndex({field:1})  
db.collection_name.dropIndex({field:1})

 

三、MongoDB API

0、复习API构造函数、连接函数、插入、删除

1)构造函数
DBClientConnection(bool auto_connect, 0, double so_timeout);
auto_connect(IN):连接失败后自动重连
so_timeout(IN):非连接超时,tcp的读写超时

2)连接函数
bool connect(string server, &string errmsg);
返回值:成功/失败
server(IN):连接的服务器
errmsg(OUT):出错信息

》示例:
bool auto_connect = true;
double so_timeout = 3;
string host = "127.0.0.1";
string port = "27017";
string errmsg = "";
DBClientConnection pConn = new DBClientConnection(auto_connect, 0, so_timeout);
pConn->connect(host+":"+port, errmsg);

3)插入
void insert(const string &ns, BSONObj obj, int flags);
ns(IN):命名空间,db_name.collection_name
obj(IN):插入的列
flags(IN):详见API文档,默认填零即可

》示例:
BSONObj insert = BSON("uid"<<10001<<"name"<<"skean1017");
pConn->insert(db+"."+collection, insert, 0);
其效果相当于:
insert into shool.student (uid, name) values (10001, “skean1017″);

4)删除
void remove(const string &ns, Query query, bool justOne);
ns(IN):命名空间,db_name.collection_name
query(IN):查询条件
justOne(IN):是否只删除匹配的第一条

》示例:
Query query = QUERY("name"<<"skean1017");
pConn->remove(db+"."+collection, query, true);
其效果相当于:
delete from shool.student where name=”skean1017″;

1、通过API修改数据和查询分析

--修改

void update( const string &ns,Query query,BSONObj obj,bool upsert = false, bool multi = false );
○ ns  库名.集合名
○ obj BSON对象
○ upsert 如果条件不成立是否新增,默认false
○ multi 是否更新多条,默认false

》示例:
Query query = QUERY("uid"<<10001);
BSONObj obj = BSON("$set"<update(db+"."+collection, query, obj, false, false);
其效果相当于:
update shool.student set name=”habadog1203” where uid=10001;

 

--查询

virtual auto_ptr<DBClientCursor> query(const string &ns, Query query=Query() , int nToReturn = 0, int nToSkip = 0,const BSONObj *fieldsToReturn = 0, int queryOptions = 0 , int batchSize = 0 ) {            checkConnection();
return DBClientBase::query( ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions , batchSize );    
}
—auto_ptr<DBClientCursor>  智能指针,自动释放<>内部的内存数据
—cusor 游标
—DBClientCursor 类
○ more()如果为真,调用next是安全的
○ next()返回BSONObj 对象
——query函数参数
○ ns 库名.集合名
○ query 查询条件
○ nToReturn  返回记录数
○ nToSkip   跳过的记录数
○ fieldsToReturn 要返回的字段

》示例:
string db = "shool";
string collection = "student";
Query condition = QUERY("age"<<20);
int limit = 10;
int offset = 5;
BSONObj columns = BSON("uid"<<1<<"name"<<1);
auto_ptr cursor;
cursor = pConn->query(db+"."+collection, condition, limit, offset, columns, 0, 0);
其效果相当于:
select uid,name from shool.student where age=20 limit 5,10;
对结果集的操作:
int uid=0;
string name="";
while(cursor->more())
{
    BSONObj p = cursor->next();
    uid = p["uid"].Int();
    name = p["name"].String();
    count << uid << " " << name << endl;
}

 

2、通过API查询文档

--BSONObj对象
○ BSONElement getField(const StringData& name) const;  获得对应字段

思路:通过getField 获得BSONElement(元素)对象,调用String(),Number()精确获得各个值?

但是,如果有的数据没有age,这样调用有问题:

——解决:需要调用hasField(char*)或hasElement(char*)来判断是否有该元素

 

3、通过API查询文档、内容解析、异常捕捉

》解析文档流程:

 

 

》mongodb的api的异常处理
mongodb为我们提供了DBException异常类,如果有错误会进行抛出,我们可以通过try catch的方式捕捉该类错误,然后通过打印 what()显示错误详细信息.具体所在头文件: assert_util.h.除了捕获mongo提供的异常信息,还需要捕获标准库的错误信息,最后有一个兜底的所有异常捕捉.
使用方法:
catch( mongo::DBException& e ) {
    printf("MONGO Exception(set): %s\n", e.what());
    return -1;
}
catch (std::exception& e) {
    printf("MONGO Exception(set): %s\n", e.what());
    return -1;
}
catch (...){
    printf(“MONGO Exception\n”);
    return -1;
}

 

》头文件准备:

--在VS中更改main.cpp

#include <iostream>
#include <string>
#include <mongo/client/dbclient.h>

using namespace std;
using namespace mongo;

int main(int argc,char *argv[])
{
    if (argc != 2){
        cout << "./main 1|2|3|4 ---- 1-insert,2-remove,3-update,4-query" << endl;
        return -1;
    }
    int op = atoi(argv[1]);
    
    //构造连接
    DBClientConnection conn(false,0,3);
    std::string errmsg;
    if (!conn.connect("localhost:27018", errmsg)){//模拟一下错误端口27018
        cout << "connect to mongo err" << endl;
        //return -1;
    }
    cout << "connect ok" << endl;
    try{

    
        if (op == 1){
            //insert 
            //第一种玩法
            BSONObjBuilder b1;
            b1.append("id", 1);
            b1.append("name", "yekai");//{id:1,name:'yekai'}
            conn.insert("yekai.langzi", b1.obj());
            //第二种玩法
            BSONObjBuilder b2;
            b2 << "id" << 2 << "name" << "fuhongxue";
            conn.insert("yekai.langzi", b2.obj());
            //第三种玩法
            conn.insert("yekai.langzi", BSON("id" << 3 << "name" << "luxiaojia"));
            //第四种玩法
            Query ins("{id:4,name:'lixunhuan',age:50,info:{like:'drink',wuqi:'feidao'}}");
            conn.insert("yekai.langzi", ins.obj);
        }
        else if (op == 2){
            //remove
            //删除id》=2 {id:{$gte:2}}
            Query qry("{id:{$gte:2}}");
            conn.remove("yekai.biancheng", qry);
        }
        else if (op == 3){
            //update 
            Query qry("{id:1}");//查询条件
            //Query bobj("{$set:{name:'fuhongxue'}}");//更新的内容
            Query bobj("{name:'fuhongxue'}");//更新的内容
            conn.update("yekai.langzi", qry, bobj.obj);
        }
        else if (op == 4){
            //query 
            auto_ptr<DBClientCursor> cursor = conn.query("yekai.langzi", Query("{}"));

            while (cursor->more()){//判断是否有下一条
                mongo::BSONObj obj = cursor->next();//取下一条记录,为BSONObj格式
                //cout << obj << endl;
                //解析数据
                cout << "id:" << obj.getField("id").Number() << ",name:" << obj.getField("name").String();
                if (obj.hasElement("age")){//是否存在该元素
                    cout << ",age:" << obj.getField("age").Number();
                }
                
                if (obj.hasElement("info")){
                    cout << ",info:{ like:" << obj["info"]["like"].String() << ",wuqi:" << obj["info"]["wuqi"].String()<<"}";//使用重载操作符[]
                }
                cout << endl;
            }
        }
    }
    catch (mongo::DBException& e) {
        printf("MONGO Exception(set): %s\n", e.what());
        return -1;
    }
    catch (std::exception& e) {
        printf("MONGO STD Exception(set): %s\n", e.what());
        return -1;
    }
    catch (...){
        printf("MONGO Exception\n");
        return -1;
    }

    return 0;
}
main.cpp

原终端改变前后数据(>db.langzi.find())对比。

将main.cpp传至Linux上,然后打开另一个终端重新编译,执行shell>./main 4)

 

四、案例开发(网盘-服务器端)

1、案例需求分析、模型设计

》需求总体描述
开发类似于网盘功能,支持文件(图片,视频,mp3等)的上传和下载(MongoDB的优势)。

》功能需求
支持多用户
1)用户的校验,必须是注册用户,用户名和密码正确才能上传和下载。(注册部分正常需要web前端开发,该案列不做注册部分功能,直接在mysql的用户表增加记录即可)。
2)查看登陆用户上传的文件信息。(支持命令行的方式查看即可,不需要做web前端),实现管理台。
3)上传文件
4)下载上传过的文件到本地。
5)删除上传的文件。(可根据情况是否添加,不是必须)


》技术实现要求
Mysql+mongo
用mysql存储用户的信息,文件上传和下载的对应关系(本地和mongo中文件的对应关系)
Mongo存放文件。

》流程
需求接收-需求分析-概要设计-详细设计-编码-测试-上线-维护-------------下线

 

》可行性分析:
  工期评估 人月
  技术可行性:
  ○ BSONObj storeFile( const string& fileName , const string& remoteName="" , const string& contentType="");  上传GridFS
  ○ gridfs_offset write( const string& where ) const; 下载GridFile

功能设计,模块设计,模型设计

》设计功能:
○ 用户验证
○ 上传
○ 下载
○ 查看
○ 删除(二期)

》模块设计:
○ 设计2个类
  ▪ mysql 操作mysql数据库  用户验证,保存文件信息,查询文件信息
  ▪ mongo 操作mongo数据库  存文件,下载文件

》模型设计:
○ 参考功能
○ 用户验证  设计用户信息表

用户信息表:用户id,用户姓名,密码,手机号,公司,邮箱,备注

create table t_user_info( user_id varchar(30),
user_name varchar(50),
pass_word varchar(16),
remark varchar(100)
);
○ 文件信息查看设计文件信息表(mysql)

文件信息表:本地文件名,文件类型,大小,上传时间,修改时间,下载次数,用户id,mongo文件名,备注

create table t_file_info(
file_id int primary key auto_increment,
local_file_name varchar(50),
mongo_file_name varchar(50),
file_size int,
upload_date timestamp,
user_id  varchar(30),
remark varchar(100)
);

 

打开VS2015,新建项目:选择“Visusl C++”,右侧选择“空项目”,名称:ods,位置改为project所在目录(我的为 F:\Download\06-数据库编程day06(案例开发)\4-源码\project);

创建成功后,在“ods”右键选择“属性”,选择“VC++目录”进行配置:选择“包含目录”,在其后加入到include一级的目录(最好是相对路径,我的为 ..\..\mongo\include);

在“ods”右键添加源文件:main.cpp,然后编写代码。

 

》建库建表(Linux登录MySQL)

shell>mysql -u root -p(输入密码)
mysql> show databases;
mysql> create database ods character set utf8;(建库:ods—online database store)
mysql> use ods;(切库)
mysql> create table t_user_info( user_id varchar(30), user_name varchar(50), pass_word varchar(16), remark varchar(100) );
mysql> create table t_file_info( file_id int primary key auto_increment, local_file_name varchar(50), mongo_file_name varchar(50), file_size int, upload_date timestamp, user_id  varchar(30), remark varchar(100) );

 

2、搭建框架

》(管理台)设计指令:
-上传upload srcfile mongofile
-下载download mongofile desfile
-查看  list
-退出 quit
-删除 delete mongofile  localfile(二期)

 

》编写main.cpp

#include <iostream>
#include <vector>
#include <string>

using namespace std;

void splitString(const char *Src, char delim, vector<string> &vsplit)
{
    string tmp = Src;
    vsplit.clear();
    int index = 0;
    size_t last = 0;
    last = tmp.find_first_not_of(delim, last);//找到第一个不为分隔符的字符
    index = tmp.find_first_of(delim, last);//找到第一个分隔符
    while (index != string::npos)//npos代表字符串的结尾
    {
        string target = tmp.substr(last, index - last);
        vsplit.push_back(target);

        //last = index +1;
        last = tmp.find_first_not_of(delim, index);
        index = tmp.find_first_of(delim, last);

    }
    if (index == string::npos && tmp.length() > last)//到末尾了,如果整个长度大于last坐标,说明还有最后一个字符要放到vector
    {
        vsplit.push_back(tmp.substr(last));
    }
#if 1
    cout << vsplit.size() << endl;
    for (size_t i = 0; i < vsplit.size(); i++)
    {
        cout << "i=" << i << "," << vsplit[i].c_str() << endl;
    }
#endif
}

/*
- 上传 upload srcfile mongofile
- 下载 download mongofile desfile
- 查看  list
- 退出 quit
删除 delete mongofile  localfile(二期)
*/

int main(int argc,char *argv[])
{
    if (argc != 3){
        cout << "./main user passwd" << endl;
        return -1;
    }
    string line;
    vector<string> vCmd;

    while (1){//进入管理台
        cout << "ods>";
        getline(cin, line);//获取行,指令
        splitString(line.c_str(), ' ', vCmd);//拆分命令
        if (vCmd[0].compare("quit") == 0){
            //quit
            cout << "bye bye" << endl;
            break;
        }
        else if (vCmd[0].compare("upload") == 0){
            //上传

        }
        else if (vCmd[0].compare("download") == 0){
            //下载

        }
        else if (vCmd[0].compare("list") == 0){
            //查看

        }

    }
    return 0;
}
main.cpp

shell>mkdir day06
上传main.cpp至day06文件夹下
shell>g++ main.cpp -o main
shell>./main 11 22
ods>list

 

3、MySQL端登录实现

shell>locate mysql.h(然后把/usr/include的mysql目录及其下文件下载到project目录下,然后在ods的属性页的“VC++”目录,包含目录,添加:..\..\mysql)

在VS的“ods”处右键“添加类”,然后保持默认(左侧选择“Visual C++”下的“C++”,右侧C++类),点击“添加”;类名输入:CCMysql,点击“完成”,会生成CMysql.h和CMysql.cpp:

 


》添加用户和密码:
mysql> desc t_user_info;
mysql> insert into t_user_info values('yekai','叶开','123','bianchenglangzi');
mysql> insert into t_user_info values('fuhongxue','傅红雪','456','bianchenglangzi');


编写CMysql.h

#pragma once


class CCMysql
{
public:
    CCMysql();
    int UserLogin(const char *User,const char *Passwd);
    ~CCMysql();
};
CMysql.h

编写CMysql.cpp

#include "CMysql.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h>

MYSQL *mysql = NULL;

CCMysql::CCMysql()
{
    mysql = mysql_init(NULL);
    if (mysql == NULL){
        printf("mysql init err");
        exit(1);
    }
    mysql = mysql_real_connect(mysql, "localhost", "root", "123", "ods", 0, NULL, 0);
    if (mysql == NULL){
        printf("mysql connect err");
        exit(1);
    }
}


CCMysql::~CCMysql()
{
    if (mysql){
        mysql_close(mysql);
    }
}
//用户登陆
int CCMysql::UserLogin(const char *User, const char *Passwd)
{
    //用户名和密码匹配
    //执行该sql:select * from t_user_info where user_id='yekai' and pass_word='123';
    //如果有结果集,代表匹配
    char rSql[512] = { 0 };
    
    sprintf(rSql, "select user_id from t_user_info where user_id='%s' and pass_word='%s'", User, Passwd);
    printf("%s\n", rSql);
    if (mysql_query(mysql, rSql)){
        printf("mysql exe err:%s\n", rSql);
        return -1;
    }
    
    MYSQL_RES *result = mysql_store_result(mysql);//取结果集
    if (result != NULL){//该指针为空并非代表准确,有结果集,但结果集没有记录
        return (int)result->row_count;
    }
    return 0;// 代表结果不匹配
}
CMysql.cpp

 

》编译:

shell>touch makefile

shell>vi makefile

#SrcFiles=$(wildcard *.c)

IncPath=/usr/include/mysql
LibPath=/usr/lib64/mysql
PubLib=-lmysqlclient -lstdc++ -ldl -lpthread -lrt

all:main
main:main.cpp CMysql.cpp
    gcc -o $@ $^ -I$(IncPath) -L$(LibPath) $(PubLib)

clean:
    -rm -f main

 

》扩展:SQL注入

mysql> ./main yekai " 0' or '1=1"

 

4、SQL注入问题解决

》分析:SQL注入在于登录语句中含有or,所以如果判断密码处含有or,报错。

#include "CMysql.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h>

MYSQL *mysql = NULL;

CCMysql::CCMysql()
{
    mysql = mysql_init(NULL);
    if (mysql == NULL){
        printf("mysql init err");
        exit(1);
    }
    mysql = mysql_real_connect(mysql, "localhost", "root", "123", "ods", 0, NULL, 0);
    if (mysql == NULL){
        printf("mysql connect err");
        exit(1);
    }
}


CCMysql::~CCMysql()
{
    if (mysql){
        mysql_close(mysql);
    }
}
//用户登陆
int CCMysql::UserLogin(const char *User, const char *Passwd)
{
    //用户名和密码匹配
    //执行该sql:select * from t_user_info where user_id='yekai' and pass_word='123';
    //如果有结果集,代表匹配
    if (strstr(Passwd, " or ")){
        printf("zhe yang bu hao!\n");
        return 0;
    }
    char rSql[512] = { 0 };
    
    sprintf(rSql, "select user_id from t_user_info where user_id='%s' and pass_word='%s'", User, Passwd);
    printf("%s\n", rSql);
    if (mysql_query(mysql, rSql)){
        printf("mysql exe err:%s\n", rSql);
        return -1;
    }
    
    MYSQL_RES *result = mysql_store_result(mysql);//取结果集
    if (result != NULL){//该指针为空并非代表准确,有结果集,但结果集没有记录
        return (int)result->row_count;
    }
    return 0;// 代表结果不匹配
}
CMysql.cpp

 

5、查看功能实现

CMysql.h中增加:

    int ListFileInfo(const char *User);

CMysql.cpp中增加:

int CCMysql::ListFileInfo(const char *User)
{
    //select * from t_file_info where user_id='yekai';
    //执行上面的sql,显示结果集
    char rSql[512] = { 0 };
    sprintf(rSql, "select * from t_file_info where user_id='%s'", User);
    if (mysql_query(mysql, rSql)){
        printf("query err:%s\n", rSql);
        return -1;
    }

    MYSQL_RES *result = mysql_store_result(mysql);//取结果集
    if (result != NULL){//该指针为空并非代表准确,有结果集,但结果集没有记录
        MYSQL_ROW row;
        unsigned int num_fields;
        unsigned int i;

        num_fields = mysql_num_fields(result);
        while ((row = mysql_fetch_row(result)))
        {
            unsigned long *lengths;
            lengths = mysql_fetch_lengths(result);
            for (i = 0; i < num_fields; i++)
            {
                printf("%s\t",  row[i] ? row[i] : "NULL");
            }
            printf("\n");
        }
    }
    

    return 0;
}

main.cpp中增加:

#include "CMysql.h"        

else if (vCmd[0].compare("list") == 0){ //查看 //cout << vCmd[0] << endl; cmysql.ListFileInfo(argv[1]); }

mysql> insert into t_file_info(local_file_name,mongo_file_name,file_size,user_id,remark) ('xxx.11','yyy.11',1024,'yekai','upload sucess');
mysql> insert into t_file_info(local_file_name,mongo_file_name,file_size,user_id,remark) ('xxx.22','yyy.2',10240,'fuhongxue','upload sucess');

打开另一个终端,查看:

 

6、MySQL侧实现上传功能

》查看文件信息,看需要上传哪些信息

(t_file_info表增加status状态信息)

mysql> alter table t_file_info add column status varchar(2);

》上传设计:

第一步:
  先插入对应关系,状态填0,代表正在上传,
第二步:
  mongo上传文件
第三步:
  更新文件对应关系,文件大小,status 上传成功 1,remark 上传成功

上传和下载一块做:(打开另一个终端方便查看,先输入update语句测试)

CMysql.h中增加:

    int UploadFile(const char *User,const char *LocalFile,const char *MongoFile);
    int UpdateFileInfo(myulong FileSize, const char *User, const char *LocalFile, const char *MongoFile);

CMysql.cpp中增加:

int CCMysql::UploadFile(const char *User, const char *LocalFile, const char *MongoFile)
{
    //insert into t_file_info(local_file_name, mongo_file_name, file_size, user_id,status, remark)
    //values('xxx.11', 'yyy.11', 1024, 'yekai', '0','upload sucess');
    //需要执行上述insert语句,代表上传文件状态
    char rSql[512] = { 0 };
    sprintf(rSql, "insert into t_file_info(local_file_name, mongo_file_name, file_size, user_id,status, remark)" 
                  "values('%s', '%s', 0, '%s', '0','uploading')", LocalFile, MongoFile, User);

    if (mysql_query(mysql, rSql)){
        printf("run upload err:%s\n", rSql);
        return -1;
    }

    return 0;
}

int CCMysql::UpdateFileInfo(myulong FileSize, const char *User, const char *LocalFile, const char *MongoFile)
{
    //update t_file_info set file_size=1011,status='1',remark='upload sucess' 
    //where user_id='yekai' and local_file_name='xxx.11' and mongo_file_name='yyy.11';
    char rSql[512] = { 0 };
    sprintf(rSql, "update t_file_info set file_size=%lld,status='1',remark='upload sucess'"
        "where user_id='%s' and local_file_name='%s' and mongo_file_name='%s'", FileSize, User, LocalFile, MongoFile);
    if (mysql_query(mysql, rSql)){
        printf("run update err:%s\n", rSql);
        return -1;
    }
    return 0;
}

main.cpp中增加:

        else if (vCmd[0].compare("upload") == 0){
            //上传
            cout << "upoload:" << vCmd[1] << "," << vCmd[2] << endl;
            //1. mysql 执行  insert
            cmysql.UploadFile(argv[1], vCmd[1].c_str(), vCmd[2].c_str());
            //2. mongo 上传 文件

            //3. mysql 执行 update
            //stat 
            cmysql.UpdateFileInfo(llsize, argv[1], vCmd[1].c_str(), vCmd[2].c_str());
        }

 

7、上传文件MongoDB侧实现

在VS的“ods”处右键“添加类”,然后保持默认(左侧选择“Visual C++”下的“C++”,右侧C++类),点击“添加”;类名输入:CCMongo,点击“完成”,会生成CMongo.h和CMongo.cpp:

CMongo.h中增加:

#pragma once
#include <iostream>
#include <mongo/client/dbclient.h>
#include <string>
using namespace std;


class CCMongo
{
public:
    CCMongo();
    int UploadFile(const char *LocalFile, const char *MongoFile);
    ~CCMongo();
};
CMongo.h

CMongo.cpp中增加:

#include "CMongo.h"
#include <stdlib.h>


using namespace mongo;
DBClientConnection *conn = NULL;

CCMongo::CCMongo()
{
    conn = new DBClientConnection(false, 0, 3);
    std::string errmsg;
    if (!conn->connect("localhost", errmsg)){
        cout << "connect to mongo err:" << errmsg << endl;
        exit(1);
    }
}


CCMongo::~CCMongo()
{
    if (conn){
        delete conn;
        conn = NULL;
    }
}

mongoulong CCMongo::UploadFile(const char *LocalFile, const char *MongoFile)
{
    //构造 GridFS对象
    mongo::GridFS gfs(*conn, "ods");
    //上传文件
    gfs.storeFile(LocalFile, MongoFile);

    return 0;
}
CMongo.cpp

 

8、MySQL与MongoDB类的调用

》获取文件大小及更改:

CMongo.h中增加及修改:

#pragma once
#include <iostream>
#include <mongo/client/dbclient.h>
#include <string>
using namespace std;

typedef unsigned long long mongoulong;

class CCMongo
{
public:
    CCMongo();
    mongoulong UploadFile(const char *LocalFile, const char *MongoFile);
    ~CCMongo();
};

CMongo.cpp中增加及修改:

#include "CMongo.h"
#include <stdlib.h>


using namespace mongo;
DBClientConnection *conn = NULL;

CCMongo::CCMongo()
{
    conn = new DBClientConnection(false, 0, 3);
    std::string errmsg;
    if (!conn->connect("localhost", errmsg)){
        cout << "connect to mongo err:" << errmsg << endl;
        exit(1);
    }
}


CCMongo::~CCMongo()
{
    if (conn){
        delete conn;
        conn = NULL;
    }
}

mongoulong CCMongo::UploadFile(const char *LocalFile, const char *MongoFile)
{
    //构造 GridFS对象
    mongo::GridFS gfs(*conn, "ods");
    //上传文件
    mongo::BSONObj obj = gfs.storeFile(LocalFile, MongoFile);

    //GridFile findFile( BSONObj query ) const;
    return gfs.findFile(obj).getContentLength();//返回文件大小
    //return 0;
}

main.cpp中增加:

#include "CMongo.h"

        else if (vCmd[0].compare("upload") == 0){
            //上传
            cout << "upoload:" << vCmd[1] << "," << vCmd[2] << endl;
            //1. mysql 执行  insert
            cmysql.UploadFile(argv[1], vCmd[1].c_str(), vCmd[2].c_str());
            //2. mongo 上传 文件
            myulong llsize  =cmongo.UploadFile(vCmd[1].c_str(), vCmd[2].c_str());
            //3. mysql 执行 update
            //stat 也可以使用其获取文件大小
            cmysql.UpdateFileInfo(llsize, argv[1], vCmd[1].c_str(), vCmd[2].c_str());
        }

 

9、上传测试成功

makefile中更改:

#SrcFiles=$(wildcard *.c)


IncPath=-I/usr/include/mysql -I/home/itcast/driver/mongo/include -I/home/itcast/driver/boost/include
LibPath=-L/usr/lib64/mysql -L/home/itcast/driver/boost/lib -L/home/itcast/driver/mongo/lib
PubLib=-lmysqlclient  -ldl -lpthread -lrt -lmongoclient -lboost_thread -lboost_filesystem -lboost_program_options

all:main
main:main.cpp CMysql.cpp CMongo.cpp
    g++ -o $@ $^ $(IncPath) $(LibPath) $(PubLib)

clean:
    -rm -f main

上传文件后重新编译

上传一张图片到day06后测试(如:ywbg.jpg)

打开另一个终端,登录mysql查看是否上传成功:

再打开第三个终端,登录MongoDB查看mongo端是否上传成功

 

10、下载功能实现

CMongo.h中增加:

    int downloadFile(const char *MongoFile,const char *DesFile);

CMongo.cpp中增加:

int CCMongo::downloadFile(const char *MongoFile, const char *DesFile)
{
    //通过gridfs 查找文件获得 gridfile 对象,write 就ok了
    //构造 GridFS对象
    mongo::GridFS gfs(*conn, "ods");
    gfs.findFile(MongoFile).write(DesFile);
    return 0;
}

main.cpp中增加

        else if (vCmd[0].compare("download") == 0){
            //下载
            cout << "download:" << vCmd[1] << "," << vCmd[2] << endl;
            cmongo.downloadFile(vCmd[1].c_str(), vCmd[2].c_str());
        }

上传文件,编译登录:

1)测试下载文件(先测试下载一张图片,如:刚才上传的ywbg.jpg)

另打开一个终端,查看是否下载成功:

将图片(下载)到本地Windows系统查看,(点击)看是否正常在Windows显示:

2)测试下载文件(先上传一部电影到day06,然后测试下载一部电影,如:hzw763.mp4)

再打开一个终端(第2个终端),切换到day06目录下,查看文件大小。然后登录MongoDB(当前只有之前上传成功的图片ywbg.jpg)

然后在原终端(即登录yekai 123)上传文件

然后打开第三个终端,登录mysql查看文件上传状态:(注意:此时文件大小为0!

等待原终端(即登录yekai 123)上传成功:(出现ods> 即上传成功)

在之前打开的第3个终端(登录MySQL那个)查看文件上传状态:

查看第2个终端(登录MongoDB的那个)查看文件上传情况:

测试下载:

在原终端(即登录yekai 123)下载hzw763.mp4

查看第2个终端(登录MongoDB的那个,退出quit,然后查看)查看文件下载情况:

将电影(下载)到本地Windows系统查看,(点击)看是否正常在Windows播放。

 

11、总结

1)MySQL库和MongoDB库本身没有关系,是通过上传下载建立的联系。

2)MD5,MongoDB上传成功后会生成一个md5,可以通过md5去判断在当前文件夹文件是否已经下载。

3)删除(二期),在MySQL和MongoDB两个数据库都要删除,在两个数据库都留一个接口,根据命令行设计删除指令,然后在main函数调用一下。

 

在学习数据库编程总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

posted on 2020-07-22 09:50  Alliswell_WP  阅读(360)  评论(0编辑  收藏  举报

导航