共享单车(八):数据库

实现后台数据库访问模块的框架,能够实现验证请求并响应(支持数据库操作)。
在这里插入图片描述

数据库设计

class SqlTabel	//负责数据库表的创建
{
public:
	SqlTabel(std::shared_ptr<MysqlConnection> sqlconn) :sqlconn_(sqlconn) {}

	bool CreateUserInfo()        //创建用户表
	{
		const char* pUserInfoTabel = " \
									 CREATE TABLE IF NOT EXISTS userinfo( \
									 id            int(16)          NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT'用户id', \
                                     mobile        varchar(16)      NOT NULL DEFAULT '13000000000' COMMENT'手机号', \
                                     username      varchar(128)     NOT NULL DEFAULT '' COMMENT'用户名', \
                                     verify        int(4)           NOT NULL DEFAULT 0 COMMENT'验证',  \
                                     registertm    timestamp        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT'注册时间', \
                                     money         int(4)           NOT NULL DEFAULT 0 COMMENT'余额', \
                                     INDEX         mobile_index(mobile)   \
					                 )";
		if (!sqlconn_->Execute(pUserInfoTabel))
		{
			LOG_ERROR("create table userinfo table failed. error msg: %s", sqlconn_->GetErrInfo());
			return false;
		}
		return true;
	}

	bool CreateBikeTable()        //创建单车表
	{
		const char* pBikeInfoTabel = " \
			                         CREATE TABLE IF NOT EXISTS bikeInfo( \
	                                 id            int              NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT'单车id', \
			                         devno         int              NOT NULL COMMENT'单车编号', \
                                     status        tinyint(1)       NOT NULL DEFAULT 0 COMMENT'单车状态', \
                                     trouble       int              NOT NULL DEFAULT 0 COMMENT'损坏类型编号', \
                                     tmsg          varchar(256)     NOT NULL DEFAULT '' COMMENT'损坏原因描述', \
                                     latitude      double(10, 6)    NOT NULL DEFAULT 0 COMMENT'维度', \
                                     longitude     double(10, 6)    NOT NULL DEFAULT 0 COMMENT'经度', \
                                     UNIQUE(devno)    \
                                     )";
		if (!sqlconn_->Execute(pBikeInfoTabel))
		{
			LOG_ERROR("create table bikeinfo table failed. error msg: %s", sqlconn_->GetErrInfo());
			return false;
		}
		return true;
	}

private:
	std::shared_ptr<MysqlConnection> sqlconn_;
};

数据库访问

class SqlRecordSet {	//数据库访问接口
public:
	SqlRecordSet() :m_pRes(NULL)
	{

	}

	explicit SqlRecordSet(MYSQL_RES* pRes)// 不能隐式构造
	{
		m_pRes = pRes;
	}
	MYSQL_RES* MysqlRes()
	{
		return m_pRes;
	}
	~SqlRecordSet() {
		if (m_pRes)
		{
			mysql_free_result(m_pRes);	// 释放一个结果集合使用的内存
		}
	}

	/*
	* 你已经设置了结果集,此时若要再次设置结果集,那么之前的结果集就访问不到了.(那之前的结果集访问不到了,之间的结果集还没来的及释放,就是内存泄漏)
	* 所以,你要设置结果集的前提是:结果集是空的.
	* 不是空的,咱们不让他设置
	*/
	//设置结果集
	inline void SetResult(MYSQL_RES* pRes)
	{
		//如果此时已经保存了结果集,那么就应该让程序报错,防止内存泄漏
		assert(m_pRes == NULL);
		if (m_pRes)
		{
			LOG_WARN("the MYSQL_RES has already stored result , maybe will case memory leak\n");
		}
		m_pRes = pRes;
	}
	//获取结果集
	inline MYSQL_RES* GetResult()
	{
		return m_pRes;
	}

	//获取里面的行
	void FetchRow(MYSQL_ROW& row)
	{
		row = mysql_fetch_row(m_pRes);	// 检索结果集的下一行
	}

	//返回具体行的数量
	inline i32 GetRowCount()
	{
		return m_pRes->row_count;
	}
private:
	MYSQL_RES* m_pRes;	// 存放mysql结果集的数据结构
};

协调处理事务

class BusinessProcessor	//负责协调处理事务
{
public:
	BusinessProcessor(std::shared_ptr<MysqlConnection> conn);

	bool init();

	virtual ~BusinessProcessor();

private:
	std::shared_ptr<MysqlConnection> mysqlconn_;	//数据库连接
	std::shared_ptr<UserEventHandler> ueh_;        //用户事件处理器
	//...可以增添其它事件处理器
};

数据库操作

class MysqlConnection {
public:
	MysqlConnection();
	~MysqlConnection();

	MYSQL* Mysql()
	{
		return mysql_;
	}
	//初始化
	bool Init(const char* szHost, int nPort, const char* szUser, const char* szPasswd, const char* szDb);	

	//不需要/需要拿到结果
	bool Execute(const char* szSql);
	//MYSQL_RES *
	bool Execute(const char* szSql, SqlRecordSet& recordSet);

	//将pSrc特殊字符进行转义,一些特殊字符如果不转义,sql查询就会报错
	int EscapeString(const char* pSrc, int nSrcLen, char* pDest);

	void Close();
	//得到错误信息的方法
	const char* GetErrInfo();

	//服务断掉了,重连
	void Reconnect();
private:
	MYSQL* mysql_;//mysql的句柄,用于操作数据库
};

初始化

bool MysqlConnection::Init(const char* szHost, int nPort, const char* szUser, const char* szPasswd, const char* szDb)
{
    LOG_INFO("enter Init.\n");

    //初始化
    if (mysql_init(mysql_) == NULL) {   //  mysql_init 用来分配或者初始化一个MYSQL对象,用于连接mysql服务端->失败=NULL 成功=!NULL
        LOG_ERROR("init mysql failed %s , %d", this->GetErrInfo(), errno);
        return false;
    }

    //因为网络等原因,断开后自动重连
    char cAuto = 1;
    if (mysql_options(mysql_, MYSQL_OPT_RECONNECT, &cAuto)!=0)  // 用于设置 MySQL 连接的选项->成功返回0
    {
        LOG_ERROR("mysql_options MYSQL_OPT_RECONNEC failed.");
    }

    //连接
    //“host”的值必须是主机名或IP地址
    //“user”参数包含用户的MySQL登录ID
    //“passwd”参数包含用户的密码
    //“db”是数据库名称
    //如果“port”不是0,其值将用作TCP/IP连接的端口号
    //如果unix_socket不是NULL,该字符串描述了应使用的套接字或命名管道。
    //client_flag的值通常为0
    if (mysql_real_connect(mysql_, szHost, szUser, szPasswd, szDb, nPort, NULL, 0) == NULL) // 与运行在主机上的MySQL数据库引擎建立连接
    {
        LOG_ERROR("connect mysql failed : %s ", this->GetErrInfo());
    }

    return true;

}

查询结果

bool MysqlConnection::Execute(const char* szSql)
{
    if (mysql_real_query(mysql_, szSql, strlen(szSql)) != 0)    // 执行szSql语句->成功=0 失败=-1
    {
        if (mysql_errno(mysql_) == CR_SERVER_GONE_ERROR)//断开连接就重连
        {
            Reconnect();
        }
        return false;
    }
    return true;
}

bool MysqlConnection::Execute(const char* szSql, SqlRecordSet& recordSet)
{
    //先进行sql查询,看是否能够执行成功?
    if (mysql_real_query(mysql_, szSql, strlen(szSql)) != 0)
    {
        if (mysql_errno(mysql_) == CR_SERVER_GONE_ERROR)    // error code
        {
            Reconnect();    // 重连 
        }
        return false;
    }
    //执行成功了,就将查到的结果设置到结果集中
    MYSQL_RES* pRes = mysql_store_result(mysql_);
    if (!pRes) {
        return NULL;//设置失败,返回空,说明mysql_store_result失败了
    }
    recordSet.SetResult(pRes);//将结果放入结果集
    return false;
}

转义

/*
* pSrc  转义前的字符
* pDest 转义后的字符
*/
int MysqlConnection::EscapeString(const char* pSrc, int nSrcLen, char* pDest)
{
    if (!mysql_)
    {
        return 0;
    }
    // mysql必须是有效的开放式连接,将“from”中的字符串编码为转义SQL字符串,将结果置于“to”中,并添加1个终结用NULL字节
    return mysql_real_escape_string(mysql_, pDest, pSrc, nSrcLen);//将源src转义到目标子串dest
    
}

相关知识

1.安装mysql c++库

sudo apt-get install libmysql++-dev
sudo systemctl mysql-server

2.安装mysql

sudo apt-get install mysql-server
sudo apt-get install mysql-client
systemctl status mysql.service #请检是否安装成功

3.进入 MySQL

sudo mysql -u root -p

4.创建数据库

CREATE TABLE `users`(
    `use` VARCHAR(50) NOT NULL COMMENT 'id',
    `pwd` VARCHAR(50) NOT NULL COMMENT 'passwd',
    PRIMARY KEY (`use`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `users`(`use`,`pwd`) VALUES ('aa' , 'bb'),('cc','dd');

5.常用操作

https://learn.microsoft.com/zh-cn/azure/mysql/single-server/connect-cpp
https://blog.csdn.net/qq_60755751/article/details/136631798

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/642567.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mysql之基本架构

1.Mysql简介 mysql是一种关系型数据库&#xff0c;由表结构来存储数据与数据之间的关系&#xff0c;同时为sql(结构化查询语句)来进行数据操作。 sql语句进行操作又分为几个重要的操作类型 DQL: Data Query Language 数据查询语句 DML: Data Manipulation Language 添加、删…

Windows下安装部署rocketmq

1.1.下载安装rocketmq 下载 | RocketMQ 下载完后解压到自定义目录&#xff0c;MQ解压路径\rocketmq-all-4.6.0-bin-release&#xff1b;&#xff08;Windows10系统解压路径不要出现空格&#xff09; 1.2.配置环境变量 配置环境变量&#xff0c;变量名&#xff1a;ROCKETM…

Git 仓库中 -- 代码冲突产生、定位、解决的流程

目录 前置知识1 工具环境2 冲突的产生2.1 仓库中的源代码2.2 人员 A 首先更改代码2.3 人员 B 更改代码&#xff0c;产生冲突2.3.1 第一次错误提示&#xff1a;2.3.2 第二次错误提示&#xff1a; 3 查看冲突4 手动解决冲突4.1 方式一4.2 方式二&#xff08;tortoisegit&#xff…

mysql设置密码,修改密码,破解密码

目录 mysql官方文档 1. mysql中文文档地址&#xff1a; 2. mysql英文文档地址&#xff1a; 一、数据库设置密码&#xff1a; 1.命令行模式&#xff1a; 2.进入数据库设置密码&#xff1a; 二、数据库修改密码&#xff08;需要知道旧密码&#xff09;&#xff1a; 1.命令…

vue 展示svg矢量图可缩放拖动

使用插件&#xff1a;svg-pan-zoom <template> <!-- svg图--><div id"svgContainer"></div> </template><script> import svgPanZoom from svg-pan-zoom import svgFile from ../datav/img/220kVscb.svg // 路径根据实际情况调…

同旺科技 FLUKE ADPT 隔离版发布 ---- 说明书

所需设备&#xff1a; 1、FLUKE ADPT 隔离版 内附链接&#xff1b; 应用于&#xff1a;福禄克Fluke 12E / 15BMax / 17B Max / 101 / 106 / 107 应用于&#xff1a;福禄克Fluke 15B / 17B / 18B

Spring 事件监听

参考&#xff1a;Spring事件监听流程分析【源码浅析】_private void processbean(final string beanname, fi-CSDN博客 一、简介 Spring早期通过实现ApplicationListener接口定义监听事件&#xff0c;Spring 4.2开始通过EventListener注解实现监听事件 FunctionalInterface p…

栈和队列的经典例题,LeetCode 括号匹配问题;栈实现队列;队列实现栈;队列带环问题

1.前序 又有很久没有更新文章了&#xff0c;这次带你们手撕几道基础题&#xff1b;真的就和康纳吃饭一样简单&#xff01;&#xff01;&#xff01; 如果还不会队列和栈的可以去看看之前写的博客&#xff1b; 栈的实现 队列概念以及实现 <- 快速传送 目录 1.前序 …

HTTP响应的基本概念

目录 HTTP响应中的一些信息 HTTPS HTTP响应中的一些信息 状态码&#xff1a;描述了这次HTTP请求是否成功&#xff0c;以及失败的原因。 1&#xff09;200 ---OK 表示这次访问成功了。 2&#xff09;404 ---Not Found 表示客户端请求的资源在服务器这边不存在。 3&a…

线性表(从数据结构的三要素出发)

文章目录 逻辑结构存储结构顺序存储链式存储单链表双链表循环单链表循环双链表静态链表 数据的操作顺序结构链式结构单链表双链表 逻辑结构 线性表是具有相同数据类型的 n ( n ≥ 0 ) n(n≥0) n(n≥0)个数据元素的有限序列&#xff0c;其中 n n n为表长&#xff0c;当 n 0 n0…

KMP算法【C++】

KMP算法测试 KMP 算法详解 根据解释写出对应的C代码进行测试&#xff0c;也可以再整理成一个函数 #include <iostream> #include <vector>class KMP { private:std::string m_pat;//被匹配的字符串std::vector<std::vector<int>> m_dp;//状态二维数组…

WXSS模板样式-全局样式和局部样式

一、WXSS 1.WXSS WXSS(WeiXin Style Sheets)是一套样式语言&#xff0c;用于美化WXML的组件样式&#xff0c;类似于网页开发中的CSS 2.WXSS和CSS的关系 WXSS具有CSS大部分特性&#xff0c;同时&#xff0c;WXSS还对CSS进行了扩充以及修改&#xff0c;以适应微信小程序的开发…

NetSuite Intercompany COGS科目设置问题

在22年底的NetSuite多公司功能串讲中&#xff0c;有一个题目是Intercompany COGS科目的设置问题。近期在项目上这个问题被密集讨论。为了方便分享&#xff0c;所以在此摘出来独立成文。有兴趣的同学也可以翻看之前的视频。 NetSuite知识会 第8谈 多公司功能串讲 NetSuite Inter…

Spring6基础笔记

Spring6 Log4j2 1、概述 1.1、Spring是什么&#xff1f; Spring 是一款主流的 Java EE 轻量级开源框架 &#xff0c;Spring 由“Spring 之父”Rod Johnson 提出并创立&#xff0c;其目的是用于简化 Java 企业级应用的开发难度和开发周期。Spring的用途不仅限于服务器端的开发…

MPLS LDP原理与配置

1.LDP基本概念 &#xff08;1&#xff09;LDP协议概述 &#xff08;2&#xff09;LDP会话、LDP邻接体、LDP对等体 &#xff08;3&#xff09;LSR ID 与LDP ID &#xff08;4&#xff09;LDP消息 ⦁ 按照消息的功能&#xff0c;LDP消息一共可以分为四大类型&#xff1a;发现…

【C++STL详解(四)------vector的模拟实现】

文章目录 vector各函数接口总览vector当中的成员变量介绍默认成员函数构造函数1构造函数2构造函数3拷贝构造函数赋值运算符重载函数析构函数 迭代器相关函数begin和end 容量和大小相关函数size和capacityreserveresizeempty 修改容器内容相关函数push_backpop_backinserterases…

OpenStack平台Keystone组件的使用

1. 规划节点 安装基础服务的服务器规划 IP地址 主机名 节点 192.168.100.10 controller Openstack控制节点 2. 基础准备 使用机电云共享的单节点的openstack系统&#xff0c;自行修改虚拟网络编辑器、网络适配器&#xff0c;系统用户名&#xff1a;root&#xff0c;密…

【数据分析面试】53.推送消息的分布情况(SQL)

题目 我们有两个表&#xff0c;一个是 notification_deliveries 表&#xff0c;另一个是包含 created 和购买 conversion dates 的 users 表。如果用户没有购买&#xff0c;那么 conversion_date 列为 NULL。 编写一个查询&#xff0c;以获取用户转换前的推送通知总数的分布情…

51 单片机[4]:数码管显示

目标&#xff1a; 一次显示一个数字&#xff1a;在数码管第三位显示6.同时显示多个不同数字&#xff1a;在数码管前三位分别显示1, 2, 3. 一、认识数码管 LED数码管&#xff1a;数码管是一种简单、廉价的显示器&#xff0c;是由多个发光二极管封装在一起组成“8”字型的器件…

零拷贝(Zero-Copy)

1.背景 现在有这样一个场景&#xff0c;我们需要在本地选择一个文件后&#xff0c;然后上传到网络上。 我们再看看文件的内容数据的具体搬运过程&#xff1a; 你会发现&#xff0c;在整个文件搬运的过程中&#xff0c;发生了多次的数据拷贝和上下文转换。 4次数据拷贝&#…