01-线程池项目背景:C++的数据库操作

从0开始学习C++与数据库的联动

1.原始方式-使用MySQL Connector/C 提供的API查询

1.1 数据库预操作

我的本地电脑上有mysql数据库,里面预先创建了一个database名叫chat,用户名root,密码password。

1.2 Visual Studio预操作

在Windows上使用VS需要加一些路径之类的,这样才可以使用MySQL C API。否则,无法找到mysql.h,无法正常链接dll、lib,无法编译。

1.下载MySQL Connector/C;

2.配置包含目录和库目录:

"C/C++" -> "常规" -> "附加包含目录",添加MySQL Connector/C的include目录。

"链接器" -> "常规" -> "附加库目录",添加MySQL Connector/C的lib目录。

3.配置链接库:

在"链接器" -> "输入" -> "附加依赖项",添加以下库文件:

libmysql.lib:MySQL C API的静态库。

mysqlclient.lib:MySQL C API的动态链接库。

4.拷贝运行时依赖项: 将MySQL Connector/C的bin目录添加到系统的PATH环境变量中,并将libmysql.dll文件复制到vcxproj文件所在的目录。

1.3 简单查询程序

1.下面是一个单线程的程序,所有的数据库连接和查询都是在主线程中执行的。(里面可能有一些不安全的操作,方便理解没有管,比如close函数里传nullptr是不安全的,NULL最好改成nullptr便于与0值区分等。)

2.mysql.h声明了MYSQL、MYSQL_ROW、MYSQL_RES等结构体和一些mysql_init这样的函数,必须包含这个头文件,编译才不会出错。

https://dev.mysql.com/doc/c-api/8.0/en/c-api-basic-function-reference.html摘了一些出来,可跳转链接看具体的接口参数

结构体:

函数接口:


cpp 复制代码
#include <iostream>
#include <mysql.h> // 假设使用MySQL数据库

int main() {
    // 步骤1:建立数据库连接
    MYSQL* conn = mysql_init(NULL);
    if (conn == NULL) {
        std::cerr << "Failed to initialize MySQL connection." << std::endl;
        return -1;
    }

    if (mysql_real_connect(conn, "localhost", "root", "password", "chat", 0, NULL, 0) == NULL) {
        std::cerr << "Failed to connect to MySQL database." << std::endl;
        mysql_close(conn);
        return -1;
    }

    // 步骤2:执行SQL查询
    const char* query = "SELECT * FROM user";
    if (mysql_query(conn, query) != 0) {
        std::cerr << "Failed to execute SQL query." << std::endl;
        mysql_close(conn);
        return -1;
    }

    MYSQL_RES* result = mysql_store_result(conn);
    if (result == NULL) {
        std::cerr << "Failed to store MySQL result." << std::endl;
        mysql_close(conn);
        return -1;
    }

    // 处理查询结果
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(result)) != NULL) {
        // 处理每一行的数据
        std::cout << "Column 1: " << row[0] << ", Column 2: " << row[1] << std::endl;
    }

    // 释放查询结果
    mysql_free_result(result);

    // 步骤3:断开数据库连接
    mysql_close(conn);

    return 0;
}

2.将上述API查询封装到类里,调用自己的函数查询

上面的代码主要是用到了mysql_init,mysql_real_connect,mysql_query,mysql_store_result,mysql_free_result,mysql_close这些mysql.h里声明的一些函数。如果我们想用这些函数进行对MYSQL数据库内数据的操作,用的是MYSQL*类型的指针conn进行操作。

  1. 首先,MYSQL* conn = mysql_init(NULL);也即真正malloc了一个空间,分配和初始化了一个 MYSQL 结构体实例,并返回指向该实例的指针conn。这个实例用于存储数据库连接所需的所有信息。
  2. mysql_real_connect 函数建立实际的数据库连接,并使用 MYSQL 结构体来保存连接的详细信息。
  3. 之后,无论是查询(mysql_query)、获取结果(mysql_store_result)还是关闭连接(mysql_close),都需要使用这个 MYSQL* 类型的指针。这是因为所有这些操作都是在特定的数据库连接会话上执行的,而 conn 指针正是指向这个会话的。

那么,在此基础之上,我们可以将这些函数进一步的封装,用一个类中的成员函数去分别调用它们。具体而言,我们自己定义一个Connection类,里面放一个私有成员对象MYSQL* _conn指针,以及构造、析构、连接、更新、查询函数,而这些函数又分别调用了初始的mysql_init,mysql_real_connect,mysql_query,mysql_store_result,mysql_free_result,mysql_close这些mysql.h里声明的一些函数,调用的参数是初始函数所需的参数加上conn指针。在我们自己实现的函数里,还可以额外加一些LOG语句。当我们对这个类进行实例化的时候,用类实例.成员函数()就可以真正对数据库进行增删改查。

代码分为4个文件,Connection.h、Connection.cpp、main.cpp,以及最简单的日志打印(仅仅使用了一个宏,而未用到任何日志库。)里面把之前的store换成了use,这样可以减轻内存的使用,直接按行输出而不用保存。

Connection.cpp:

cpp 复制代码
// 实现对数据库的增删改查
#pragma once
#include <iostream>
#include "Connection.h"
#include "public.h"


//构造函数    mysql_init 函数用于初始化一个新的 MYSQL 结构体实例。这是建立数据库连接之前的准备步骤。
//分配并初始化一个新的 MYSQL 结构体,返回一个指向这个新结构体的指针;如果分配失败,返回 NULL。
Connection::Connection() {
	_conn = mysql_init(nullptr);
}

//真正的连接
bool Connection::connect(string ip, string user, string password, string dbname, unsigned short port) {
	MYSQL* p = mysql_real_connect(_conn,ip.c_str(), user.c_str(), password.c_str(), dbname.c_str(), port, nullptr, 0);//.c_str() :将string转换为 const char* 类型
	return p != nullptr;
}

//增删改,只要返回bool的一些操作
bool Connection::update(string sql) {
	if (mysql_query(_conn, sql.c_str())) {//当 mysql_query() 返回 0 时,表示查询语句成功执行
		LOG("更新失败:" + sql);
		return false;
	}
	return true;
}

//查并返回结果,实际上就是存
MYSQL_RES* Connection::query(string sql) {
	if (mysql_query(_conn, sql.c_str())) {
		LOG("查询失败:" + sql);
		return nullptr;
	}
	return mysql_use_result(_conn);
}

//析构函数(关闭连接)
Connection::~Connection() {
	if (_conn != nullptr)
		mysql_close(_conn);
}

Connection.h:

cpp 复制代码
// 实现对数据库的增删改查
#pragma once
#include <mysql.h>
#include <string>
using namespace std;

class Connection {
public:
	Connection();
	~Connection();	//析构函数(关闭连接)
	bool connect(string ip, string user, string password, string dbname, unsigned short port);	//真正的连接
	bool update(string sql);	//增删改,只要返回bool的一些操作
	MYSQL_RES* query(string sql);	//查并返回结果,实际上就是存

private:
	MYSQL* _conn;
};

public.h:

cpp 复制代码
#pragma once
#define LOG(str)\
	cout<<__FILE__<<":"<<__LINE__<<" "<<__TIMESTAMP__<<":"<<str<<endl;

main:

cpp 复制代码
#include "Connection.h"

int main() {
	Connection conn;
	conn.connect("localhost", "root", "password", "chat", 3306);

	string sql = "insert into user (name, age, sex) values ('zhang san' ,18, 'male');";
	conn.update(sql);
//这里没有测试query
	return 0;
}

可以发现原本chat database里面user表里没有数据的,执行了该程序之后成功插入了一行数据。并且,id一开始设置成了自增字段,就没有手动指定,只插入了(name, age, sex),它会自动从1开始填。

相关推荐
Rookie也要加油18 分钟前
01_SQLite
数据库·sqlite
MinBadGuy22 分钟前
【GeekBand】C++设计模式笔记5_Observer_观察者模式
c++·设计模式
liuxin3344556623 分钟前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
看山还是山,看水还是。1 小时前
MySQL 管理
数据库·笔记·mysql·adb
fishmemory7sec1 小时前
Koa2项目实战2(路由管理、项目结构优化)
数据库·mongodb·koa
momo小菜pa1 小时前
【MySQL 09】表的内外连接
数据库·mysql
Jasonakeke2 小时前
【重学 MySQL】四十九、阿里 MySQL 命名规范及 MySQL8 DDL 的原子化
数据库·mysql
程序猿小D2 小时前
第二百六十九节 JPA教程 - JPA查询OrderBy两个属性示例
java·开发语言·数据库·windows·jpa
小宇成长录2 小时前
Mysql:数据库和表增删查改基本语句
数据库·mysql·数据库备份
团儿.3 小时前
解锁MySQL高可用新境界:深入探索MHA架构的无限魅力与实战部署
数据库·mysql·架构·mysql之mha架构