私人博客定制----封装数据库接口

封装MySQLAPI

我们先把初始化句柄和断开句柄进行一个封装

  static MYSQL* MySQLInit(){    
      //1.初始化一个Mysql句柄建立连接    
      MYSQL* connect_fd = mysql_init(NULL);    
      
      //2.和数据库建立连接    
      if (mysql_real_connect(connect_fd, "127.0.0.1", "root", "123456",    
            "blog_system", 3306, NULL, 0) == NULL) {    
        printf("连接失败! %s\n", mysql_error(connect_fd));    
        return NULL;    
      
      }    
      //3.设置字符编码集    
      mysql_set_character_set(connect_fd, "utf8");    
      return connect_fd;    
    }        
      
    static void MySQLRelease(MYSQL* mysql) {    
      //释放句柄并断开连接                                                                                                                                                                                       
      mysql_close(mysql);     
                              
    }

博客表操作的实现

接下来的实现操作,我们需要借助一个库,这个库是Json库,
大概了解一下Json
上面哪个链接可以大概了解Json,json 出自 JavaScript, 是一种非常方便的键值对数据组织格式, 目前被业界广泛使用.
C++ 中可以使用 jsoncpp 这个库来解析和构造 json 数据。但是我们并不用里面提到的CJson的库,我们是用Linux下yum源中的Json库,可以通过下面这个命令进行下载

yum install jsoncpp-devel

以下的操作相关参数都同一使用Json的方式
Json::Value jsoncpp中最核心的类,Json::Value 就表示一个具体的对象,例如我们之前设计的API

{
	title:"博客标题",
	content:"博客正文",
	create_time:"创建时间",
	tag_id:"标签id"
}

为什么我们要使用Json这个库呢?
其实最大的好处就是方便我们以后进行功能上的扩展
Json可以跨语言编程

实现插入博客

我们需要把博客对象传进去,因为一些特赦字符的原因,我们先进行转义,然后进行申请空间,这里使用智能指针来帮助我们管理内存,我们就不必在考虑其中的释放问题。最后拼装sql语句并进行返回值校验
智能指针原理

bool Insert(const Json::Value& blog) {    
    // 由于博客内容中可能包含一些特殊字符(\n, '', "" 等), 会导致拼装出的 sql 语句有问题.    
    // 应该使用 mysql_real_escape_string 对 content 字段来进行转义    
    // 转义只是为了让 SQL 语句拼接正确. 实际上插入成功后数据库的内容已经自动转义回来了.    
   const std::string& content = blog["content"].asString();    
  
      // 文档上要求转义的缓冲区长度必须是之前的 2 倍 + 1    
      // 使用 unique_ptr 管理内存    
      std::unique_ptr<char> content_escape(new char[content.size() * 2 + 1]);    
     mysql_real_escape_string(mysql_, content_escape.get(), content.c_str(), content.size());    
  
      // 插入的博客内容可能较长, 需要搞个大点的缓冲区(根据用户请求的长度自适应),    
     std::unique_ptr<char> sql(new char[content.size() * 2 + 4096]);    
  
     sprintf(sql.get(), "insert into blog_table values(null, '%s', '%s', %d,'%s')",    
     blog["title"].asCString(), content_escape.get(),    
     blog["tag_id"].asInt(), blog["create_time"].asCString());    
  
     int ret = mysql_query(mysql_, sql.get());    
      if (ret != 0) {    
         printf("执行 sql 失败! sql=%s, %s\n", sql.get(), mysql_error(mysql_));    
         return false;    
       }    
    return true; 
 }    
实现查询所有博客

因为是获取所有博客内容,我们需要一个返回的结果,blogs作为输出型参数,除此之外我们还可以按照标签来筛选,初始给标签id默认为空,如果用户提供标签则进行筛选,没有提供则不进行筛选,然后执行sql语句,并判断是否成功,然后我们还需要对结果集合进行遍历打印

   bool SelectAll(Json::Value* blogs, const std::string& tag_id = "") {    
        //查找不需要太长的sql,固定长度就行了    
        char sql[1024 * 4] = {0};    
       // 可以根据 tag_id 来筛选结果    
       if (tag_id == "") {    
           //此时不需要按照标签来进行筛选    
        sprintf(sql, "select blog_id, title, tag_id, create_time from blog_table");    
       }    
      else {    
           //此时我们就要按标签进行筛选了    
        sprintf(sql, "select blog_id, title, tag_id, create_time from blog_table where tag_id = '%s'", tag_id.c_str());    
       }    
 		int ret = mysql_query(mysql_, sql);    
        if (ret != 0) {    
          printf("执行 查找 失败! %s\n", mysql_error(mysql_));    
          return false;    
  
        }    
  
        MYSQL_RES* result = mysql_store_result(mysql_);    
        if (result == NULL) {    
          printf("获取结果失败! %s\n", mysql_error(mysql_));    
          return false;    
  
        }    
        int rows = mysql_num_rows(result);    
        //把结果集合写到blogs参数中,返回给调用者    
        for (int i = 0; i < rows; ++i) {    
          MYSQL_ROW row = mysql_fetch_row(result);    
          Json::Value blog;    
          //row[]中的下标和上面的select语句中写的列顺序是相关的    
          blog["blog_id"] = atoi(row[0]);    
          blog["title"] = row[1];    
          blog["tag_id"] = atoi(row[2]);    
          blog["create_time"] = row[3];     
        // 遍历结果依次加入到 dishes 中                                                                                                                                                                      
         blogs->append(blog);    
        }    
        printf("执行查找成功\n");    
        //mysql查询的结果集合需要记得释放    
        mysql_free_result(result);    
        return 0;
   }
实现查询单个博客

我们在查看单个博客时,blog同样是输出型参数,根据当前的blog_id在数据库中找到具体的内容,博客内容通过blog参数返回给调用者。这回我们只需要拼接一条sql语句即可,然后再去遍历结果集合就可以。

bool SelectOne(int32_t blog_id, Json::Value* blog) {
  	char sql[1024 * 4] = {0};
    sprintf(sql, "select * from blog_table where blog_id = %d", blog_id);
    int ret = mysql_query(mysql_, sql);
    if (ret != 0) {
    printf("执行 sql 失败! %s\n", mysql_error(mysql_));
         return false;
    }
  
     MYSQL_RES* result = mysql_store_result(mysql_);
     if (result == NULL) {
        printf("获取结果失败! %s\n", mysql_error(mysql_));
        return false;
      }
  
     int rows = mysql_num_rows(result);
     if (rows != 1) {
         printf("查找结果不为 1 条. rows = %d!\n", rows);
         return false;
     }
  
      MYSQL_ROW row = mysql_fetch_row(result);
      (*blog)["blog_id"] = atoi(row[0]);
      (*blog)["title"] = row[1];
      (*blog)["content"] = row[2];
      (*blog)["tag_id"] = atoi(row[3]);
      (*blog)["create_time"] = row[4];
       return true;
 }
实现更新博客

因为要更新博客,涉及到有关正文的操作,所以需要先转义,然后申请空间再由智能指针管理

bool Update(const Json::Value& blog) {                                                                                                                                                    
      //此处还需要转义,                                                                                                                                                                    
      const std::string& content = blog["content"].asString();                                                                                                                              
                                                                                                                                                                                                  
      std::unique_ptr<char> content_escape(new char[content.size() * 2 + 1]);                                                                                                               
      mysql_real_escape_string(mysql_, content_escape.get(), content.c_str(), content.size());                                                                                              
                                                                                                                                                                                                  
      //插入的博客内容会有点长,我们可以尽量把缓冲区变大点                                                                                                                                  
      std::unique_ptr<char> sql(new char[content.size() * 2 + 4096]);                                                                                                                       
       //拼接sql语句                                                                                                                                                                                           
 	  sprintf(sql.get(), "update blog_table set title='%s', content='%s',tag_id=%d where blog_id=%d",                                                                                       
           blog["title"].asCString(),                                                                                                                                                        
           content_escape.get(),                                                                                                                                                             
           blog["tag_id"].asInt(),                                                                                                                                                           
           blog["blog_id"].asInt());                                                                                                                                                         
                                                                                                                                                                                                  
       int ret = mysql_query(mysql_, sql.get());                                                                                                                                             
       if (ret != 0) {                                                                                                                                                                       
           printf("执行更新博客 失败! sql=%s, %s\n", sql.get(), mysql_error(mysql_));                                                                                                          
           return false;                                                                                                                                                                                                                                                                                                                                                                    
         }                                                                                                                                                                                     
       printf("执行博客成功\n");                                                                                                                                                               
       return true;                                                                                                                                                                            
   }                             
实现删除博客
bool Delete(int blog_id) {
	char sql[1024 * 4] = {0};
	sprintf(sql, "delete from blog_table where blog_id=%d", blog_id);
	int ret = mysql_query(mysql_, sql);
	if (ret != 0) {
		printf("执行删除博客失败! sql=%s, %s\n", sql, mysql_error(mysql_));
		return false;
	}
	printf("删除博客成功\n");
	return true;
}
对博客表操作进行单元测试
void TestBlogTable(){    
      
  //方便我们进行格式化结果,打印出来的结果更好看一些    
  Json::StyledWriter writer;    
    
  MYSQL* mysql = blog_system::MySQLInit();    
  blog_system::BlogTable blog_table(mysql);    
  bool ret = false;    
    
  Json::Value blog;    
  /*    
  blog["title"] = "第一篇博客";                                                                                                                                                                                  
  blog["content"] = "我要好好学习";    
  blog["tag_id"] = 1;    
  blog["create_time"] = "2019/-/-";    
  bool ret = blog_table.Insert(blog);    
  printf("Insert:%d\n",ret);    
  */    
    
  //测试查找    
  /*Json::Value blogs;    
  ret = blog_table.SelectAll(&blogs);     
  printf("select ALl %d\n",ret);    
  printf("%s\n",writer.write(blogs).c_str());    
  */    
    
  //测试查找单个博客    
  /*ret = blog_table.SelectOne(1,&blog);    
  printf("select one %d\n",ret);    
  printf("blog:%s\n",writer.write(blog).c_str());//序列化,方便我们看输出    
  */    
  //测试修改博客
  /* blog["blog_id"] = 1;
  blog["title"] = "第一篇项目博客";
  blog["content"] = "1.博客表\n 博客'就是总结与学习',帮助我们记事。";
  ret = blog_table.Update(blog);
  printf("Update %d\n",ret);
  */

  //测试删除博客
  ret = blog_table.Delete(1);
  printf("Delete %d\n",ret);
  blog_system::MySQLRelease(mysql);
}

实现标签表的操作

实现新增标签

这块我们还是跟博客表的操作是一样的,都是拼装sql语句,然后执行,判断是否执行成功,打印提示。

bool Insert(const Json::Value& tag) {                                             
       char sql[1024 * 4] = {0};              
       // 此处 dish_ids 需要先转成字符串(本来是一个对象,    
       // 形如 [1, 2, 3]. 如果不转, 是无法 asCString)    
      sprintf(sql,"insert into tag_table values(null, '%s')",tag["tag_name"].asCString());    
      int ret = mysql_query(mysql_, sql);     
      if (ret != 0) {                         
         printf("插入标签失败! sql=%s, %s\n", sql, mysql_error(mysql_));    
         return false;                         
        }                                      
    printf("插入标签成功\n");               
    return true;                            
}         
实现删除标签
bool Delete(int32_t  tag_id) {              
      char sql[1024 * 4] = {0};    
      sprintf(sql, "delete from tag_table where tag_id = %d", tag_id);    
      int ret = mysql_query(mysql_, sql);    
      if (ret != 0) {    
         printf("插入标签失败! sql=%s, %s\n", sql, mysql_error(mysql_));    
         return false;    
       }    
    printf("插入标签成功\n");    
    return 0;  
 }
实现查看所有标签
bool SelectAll( Json::Value* tags) {    
     char sql[1024 * 4] = {0};    
     sprintf(sql, "select * from tag_table");    
     int ret = mysql_query(mysql_, sql);    
     if (ret != 0) {    
       printf("查找失败! %s\n", mysql_error(mysql_));    
         return false;    
   	}    
      MYSQL_RES* result = mysql_store_result(mysql_);    
      if (result == NULL) {    
         printf("获取结果失败! %s\n", mysql_error(mysql_));    
         return false;    
     	}    
      int rows = mysql_num_rows(result);    
      for (int i = 0; i < rows; ++i) {    
      MYSQL_ROW row = mysql_fetch_row(result);    
      Json::Value tag;    
  	  tag["tag_id"] = atoi(row[0]);    
      tag["tag_name"] = row[1];    
      tags->append(tag);    
    }    
   printf("查找标签成功!共找到 %d 个\n",rows);    
   return true;    
}    
对标签操作进行单元测试
void TestTagTable(){    
   MYSQL* mysql = blog_system::MySQLInit();    
  blog_system::TagTable tag_table(mysql);    
  Json::Value tags;    
  Json::StyledWriter writer;    
    
  /*tag["tag_name"] = "项目";    
  bool ret = tag_table.Insert(tag);    
  printf("insert %d\n",ret);    
  */    
    
  //测试查找    
 /* bool ret = tag_table.SelectAll(&tags);    
  printf("select all %d\n",ret);    
  printf("tags:%s\n",writer.write(tags).c_str());    
  */    
    
  //测试删除    
  bool ret = tag_table.Delete(1);    
  printf("Delete %d\n",ret);    
    
    
  blog_system::MySQLRelease(mysql);    
}     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值