#MySQL在C++中的基本`api`讲解

    • 一、创建驱动程序实例
    • 二、连接服务器
      • 为什么使用`tcp://`
      • 不使用`tcp://`会怎样?
      • 其他协议示例
      • 连接到具体的数据库
    • 创建SQL语句
      • Statement
      • `PreparedStatement`
      • 执行时机
    • 处理结果
        • 1. 遍历结果集
        • 2. 获取列值
        • 3. 检查结果集是否为空

​ 在上篇文章中我介绍了MySQL在C语言中的基本 api,虽然只是基本的接口,但是我们依旧可以发现有这许多问题,比如,创建对象后必须手动释放,查询结果后必须手动释放否则就会有大量的内存泄漏问题出现,当然在C语言中对于MySQL多线程的把握,需要大量的锁去实现,这不仅提高代码的复杂程度,更是进一步的把后续的维护成本大大提升。

而回看C++的三大特性,封装、继承、多态,无论是其中蕴含的RAII,对于锁的更加灵1活的使用,还是衍生出来的设计模式(如:单例模式)和池化技术,以及后对于异常的处理的都简化了代码的编写。

本文将提供一个简单的demo代码,并逐步解释其中的含义,带你快速上手基本的api

首先,确保你已经安装了MySQL Connector/C++库。可以从MySQL官网下载安装。

#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/statement.h>
#include <cppconn/resultset.h>
#include <cppconn/exception.h>
#include <iostream>int main() {try {// 创建驱动程序实例sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();// 通过驱动程序创建连接std::unique_ptr<sql::Connection> conn(driver->connect("tcp://127.0.0.1:3306", "username", "password"));// 连接到具体的数据库conn->setSchema("test_db");// 创建语句对象std::unique_ptr<sql::Statement> stmt(conn->createStatement());// 执行查询并获取结果集std::unique_ptr<sql::ResultSet> res(stmt->executeQuery("SELECT id, name FROM test_table"));// 遍历结果集并输出结果while (res->next()) {std::cout << "ID: " << res->getInt("id");std::cout << ", Name: " << res->getString("name") << std::endl;}} catch (sql::SQLException& e) {std::cerr << "SQLException: " << e.what() << std::endl;std::cerr << "SQLState: " << e.getSQLState() << std::endl;}return 0;
}

一、创建驱动程序实例

创建驱动程序实例是使用MySQL Connector/C++库与MySQL数据库进行交互的第一步。这一步骤是通过调用get_mysql_driver_instance方法来实现的。其本质是用于获取MySQL_Driver类的单例实例。这个方法确保在整个程序中只存在一个驱动程序实例。

sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();`

其中1、MySQL Connector/C++库使用了一些命名空间来组织其类和函数。sql::mysql命名空间包含了专门用于MySQL数据库的类和函数。

2、MySQL_Driver类是MySQL Connector/C++库的一个核心类,它实现了与MySQL数据库的连接管理。这个类的实例负责创建和管理与MySQL服务器的连接。

执行过程

  1. 调用get_mysql_driver_instance:
  • 当你调用sql::mysql::get_mysql_driver_instance()时,该方法会检查是否已经存在一个MySQL_Driver实例。
  • 如果不存在,它会创建一个新的实例。
  • 如果已经存在,它会返回现有的实例。
  1. 返回驱动程序实例:
  • 该方法返回一个指向MySQL_Driver实例的指针。

为什么需要驱动程序实例

驱动程序实例是与MySQL数据库通信的核心组件。通过这个实例,你可以:

  • 创建与数据库服务器的连接。
  • 执行SQL查询和命令。
  • 管理连接池和其他底层细节。

二、连接服务器

std::unique_ptr<sql::Connection> conn(driver->connect("tcp://127.0.0.1:3306", "username", "password"));
conn1->setSchema("test_db1");

这里我主要要讲一下这里的第一个参数,这个字符串由三部分组成:

  • protocol:通信协议。对于MySQL数据库,通常使用tcpsocket
  • host:数据库服务器的主机名或IP地址。
  • port:数据库服务器监听的端口号。

在这个例子中:

  • tcp:表示使用TCP/IP协议进行连接。
  • 127.0.0.1:表示连接到本地主机(localhost)。
  • 3306:MySQL数据库默认的端口号。
  • “username”:数据库的用户名。
  • “password”:数据库的密码。

为什么使用tcp://

  1. 明确通信协议:通过指定tcp://,明确告知驱动程序使用TCP/IP协议进行连接。这在需要明确区分连接方式时非常有用。例如,如果数据库服务器在本地,并且你想通过Unix域套接字(socket)连接而不是TCP/IP,可以使用socket://
  2. 灵活性和兼容性:使用标准的URL格式,可以灵活地切换不同的协议和地址,适应不同的部署环境和需求。

不使用tcp://会怎样?

如果你省略tcp://,通常默认会使用TCP/IP协议,但明确指定协议更为严谨,特别是在配置和调试数据库连接时。某些驱动程序和配置环境可能要求明确指定协议,以避免歧义或连接错误。

其他协议示例

  • socket://:用于通过Unix域套接字连接到MySQL数据库(仅适用于Unix/Linux系统)。
std::unique_ptr<sql::Connection> conn(driver->connect("socket:///path/to/socket", "username", "password"));
  • 普通连接(不指定协议):有些情况下可以省略协议前缀,依赖默认设置。
std::unique_ptr<sql::Connection> conn(driver->connect("127.0.0.1:3306", "username", "password"));

省略协议前缀通常也会使用TCP/IP协议,但明确指定协议更加严谨和可读。

连接到具体的数据库

使用创建的连接对象的 setSchema 方法选择具体的数据库。

conn1->setSchema("test_db1");

注意每个连接都是独立的,可以连接到不同的数据库实例或同一数据库实例下的不同数据库。

创建SQL语句

在C++的apisql语句分为PreparedStatement和不带参数的Statement,他们两者是有一定差别的

Statement

Statement 对象主要用于执行静态的、不带参数的 SQL 语句,例如 SELECTINSERTUPDATEDELETE。它适合用来执行那些不需要动态参数的简单 SQL 语句,其中的值是固定的,不会根据不同的输入而改变。Statement 对象的使用可以简化代码,但它不如 PreparedStatement 安全,因为不提供防止 SQL 注入的保护。

std::unique_ptr<sql::Statement> stmt(conn->createStatement());
std::unique_ptr<sql::ResultSet> res(stmt->executeQuery("SELECT id, name FROM test_table"));

在上面的demo中我们发现使用 Statement 对象时,执行 SQL 查询和获取结果是一步完成的。你需要在调用 executeQueryexecuteUpdate 等方法时传入 SQL 语句,并且方法会立即执行该语句并返回结果。

PreparedStatement

PreparedStatement主要用于参数化查询重复执行相同查询执行批量操作 等场景

// 创建 PreparedStatement 对象,并绑定 SQL 语句
std::unique_ptr<sql::PreparedStatement> pstmt(conn->prepareStatement("SELECT id, name FROM test_table WHERE id = ?"));// 第一次设置参数并执行查询
pstmt->setInt(1, 1); // 第一个参数位置,值为1
std::unique_ptr<sql::ResultSet> res1(pstmt->executeQuery());

PreparedStatement给人的感觉是像是封装了一个函数然后通过用一些set…函数经行‘传参’改变这个语句中的占位符中的字母,实现多种查询,每次查询是将占位符经行改变,而不是重新输入一个SQL语句。这样的函数有

setInt(n, 1):
设置第n个占位符(?)为整数值1。
setString(n, "Alice"):
设置第n个占位符(?)为字符串值"Alice"。
setInt(n, 25):
设置第n个占位符(?)为整数值25。
setDouble(n, 50000.50):
设置第n个占位符(?)为双精度浮点数值50000.50。
setBoolean(n, true):
设置第n个占位符(?)为布尔值true。

执行时机

  • 当调用 executeQueryexecuteUpdateexecute 方法时,SQL 语句被发送到数据库服务器并实际执行。
  • executeQuery 用于 SELECT 语句,返回一个 ResultSet 对象用于遍历查询结果。
  • executeUpdate 用于 INSERTUPDATEDELETE 等语句,返回受影响的行数。
  • execute 是一个通用方法,可以执行任何 SQL 语句,并需要根据返回结果进一步处理。

处理结果

上面我们提到在执行sql语句时会用sql::ResultSet 类型将结果封存,所以处理结果的过程,就是遍历sql::ResultSet获取值的过程。

以下是一些处理结果集的基本操作:

1. 遍历结果集

通过 next() 方法遍历结果集中的每一行:

while (res->next()) {int id = res->getInt("id");std::string name = res->getString("name");std::cout << "ID: " << id << ", Name: " << name << std::endl;
}

可以看到->next()在单个方法调用中合并了“移动到下一个元素”和“检查是否存在更多元素”这两个操作。这种设计使得遍历结果集变得简单和高效。

2. 获取列值

通过列名或列索引来获取列值:

int id = res->getInt("id"); // 使用列名
std::string name = res->getString("name");int id = res->getInt(1); // 使用列索引(从 1 开始)
std::string name = res->getString(2);
3. 检查结果集是否为空

在遍历之前可以检查结果集是否为空:

if (!res->next()) {std::cout << "No data found." << std::endl;
} else {// 重置游标到第一行res->beforeFirst();while (res->next()) {int id = res->getInt("id");std::string name = res->getString("name");std::cout << "ID: " << id << ", Name: " << name << std::endl;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux基于ALSA的声音录制

简介 linux环境使用ALSA实现声音录制&#xff0c;保存pcm到本地文件。 代码 void AudioCapture::run() {qDebug() << "AudioCapture start";snd_pcm_t *pcm_st_ nullptr;std::string device_name "default";int ret snd_pcm_open(&pcm_st_…

GCC __builtin_xxx函数

以 __builtin 开头的函数&#xff0c;这些函数是 GCC 编译器提供的一些内建函数&#xff0c;用于实现一些简单且快捷的功能&#xff0c;同时也可以用来优化编译结果。让我为您介绍一下其中一些常见的 __builtin 函数及其作用&#xff1a; __builtin_ctz(x) / __builtin_ctzll(x…

Linux基于V4L2的视频捕捉

简介 linux环境使用V4l2实现摄像头捕捉&#xff0c;界面流畅播放并可以保存图片到本地。 代码 void VideoCapture::run() {qDebug() << "VideoCapture start";// 打开设备int fd open("/dev/video0", O_RDWR);if(fd < 0){qDebug("video设…

告别暗黄,唤醒肌肤

&#x1f3ad; 想象一下&#xff0c;你的皮肤是舞台上的主角&#xff0c;但最近它似乎有些“疲惫”和“黯淡”&#xff0c;仿佛失去了往日的星光✨。别急&#xff0c;今天&#xff0c;我要为你揭秘一个能让肌肤重新焕发光彩的“魔法”——胶原蛋白&#xff01;&#x1f3a9; &a…

docker查看容器目录挂载

查看命令 docker inspect --format{{ json .Mounts }} <container_id_or_name> | jq 示例 docker inspect --format{{ json .Mounts }} af656ae540af | jq输出

Python知识点8---公共操作

提前说一点&#xff1a;如果你是专注于Python开发&#xff0c;那么本系列知识点只是带你入个门再详细的开发点就要去看其他资料了&#xff0c;而如果你和作者一样只是操作其他技术的Python API那就足够了。 Python的公共操作谁的是多种数据类型可共用的操作&#xff0c;且这些…

FreeRTOS笔记 - 二(正点原子)

一&#xff0c;任务创建和删除 具体的参数&#xff08;看视频&#xff09; 1&#xff0c;动态和静态创建的区别 动态: 任务的任务控制块以及任务的栈空间所需的内存&#xff0c;均由FreeRTOS从 FreeRTOS 管理的堆中分配。 静态: 任务的任务控制块以及任务的栈空间所需的内存&am…

vscode设置编辑器文件自动保存

步骤 1.打开vscode的设置 2.在搜索栏输入关键字“保存”&#xff1b; 在 Files: Auto Save 设置项&#xff0c;选择自动保存的模式

JavaScript中逻辑或(||)逻辑与()

在JavaScript中&#xff0c;||&#xff08;逻辑或&#xff09;和&&&#xff08;逻辑与&#xff09;是逻辑运算符&#xff0c;它们用于根据操作数的值来返回布尔值或执行短路求值&#xff08;short-circuit evaluation&#xff09;。 逻辑或&#xff08;||&#xff09;…

如何使用 PHP 函数进行网站性能监控和优化?

在构建一个高效、稳定的网站时&#xff0c;性能监控和优化是非常重要的一环。在 PHP 中&#xff0c;有许多内置函数和工具可以帮助我们实现网站的性能监控和优化。本文将介绍几种常用的 PHP 函数&#xff0c;并提供相应的代码示例&#xff0c;来帮助您更好地进行网站性能监控和…

java使用资源过高排查

在生产环境中有可能出现某java程序使用资源特别严重&#xff0c;这就需要找到该java进程&#xff0c;然后通过进程去找到是哪个线程的问题&#xff0c;这里我们就是用pidstat工具来排查一下 安装pidstat工具 yum -y install sysstat 查看java服务的pid jps 通过pid查看线…

C# WinForm —— 25 ProgressBar 介绍与使用

1. 简介 用于显示某个操作的进度 2. 常用属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到,一般以 pbar 开头ContextMenuStrip右键菜单Enabled控件是否可用ForeColor用于显示进度的颜色MarqueeAnimationSpeed进度条动画更新的速度&#xff0c;以毫秒为单位M…

Python|OpenCV-自动检测并识别车牌号(16)

前言 本文是该专栏的第18篇,后面将持续分享OpenCV计算机视觉的干货知识,记得关注。 在本文中,笔者将详细介绍如何利用OpenCV进行车牌号识别。要知道,车牌号识别是计算机视觉在交通管理领域,以及车辆监控领域的一项重要应用。车牌号识别的主要目的,在于自动检测图像中的车…

M1芯片安装Dart Tips

如果按照 Get the Dart SDK | Dart 提供的方案就会出现 ➜ ~ brew tap dart-lang/dart > Tapping dart-lang/dart Cloning into /opt/homebrew/Library/Taps/dart-lang/homebrew-dart... ^C ➜ ~ brew tap dart-lang/dart > Tapping dart-lang/dart Cloning into /opt…

JZ2440笔记:DM9000C网卡驱动

在厂家提供的dm9dev9000c.c上修改&#xff0c; 1、注释掉#ifdef MODULE #endif 2、用模块化函数修饰入口出口函数 3、在dm9000c_init入口函数&#xff0c;增加iobase (int)ioremap(0x20000000,1024);irq IRQ_EINT7; 4、一路进入&#xff0c;在dmfe_probe1中注释掉if((db…

JavaWeb学习:在SSM框架中配置一个简单的监听器和过滤器

实现效果&#xff1a; 编写一个记录有多少个请求访问的监听器&#xff0c;通过面向全部访问路径的过滤器更新监听器中的visitCount次数。 监听器&#xff1a; WebListener public class VisitCounterListener implements ServletContextListener {private static final Strin…

经常用到的代码段

opencv opencv-图像部分 opencv显示图像 cv2.namedWindow("just for test", 0) cv2.imshow("just for test", index_img) cv2.waitKey(0)Opencv转PIL.Image Image.fromarray(cv2.cvtColor(cv_img,cv2.COLOR_BGR2RGB)) PIL.Image转Opencv cv2.cvtColor(…

chatgpt :怎样学c 指针

现在的感觉&#xff0c;要想学好程序&#xff0c;必须要想法能使用ChatGPT这个工具&#xff0c;它比任何老师和书籍都有用。比Google搜索都强。它给你的答案非常全面&#xff0c;可以作为全面知识的总结。 学习C语言中的指针可以提高你的编程能力和理解计算机内存管理的知识。…

CSAPP Lab08——Proxy Lab完成思路

蓝色的思念 突然演变成了阳光的夏天 空气中的温暖不会很遥远 ——被风吹过的夏天 完整代码见&#xff1a;CSAPP/proxylab-handout at main SnowLegend-star/CSAPP (github.com) Q&#xff1a;计算机网络中port的作用是什么&#xff1f; A&#xff1a;在计算机网络中&#xff…

qt中实现多语言功能

qt中实现多语言功能 原理&#xff1a; 其本质就是生成ts文件&#xff0c;然后使用Linguist软件手工翻译&#xff0c;再生成qm文件&#xff0c;最后在主程序的开始加载不同的qm文件&#xff0c;实现多语言。 步骤&#xff1a; 修改程序文件 在pro文件中加入说明 TRANSLATI…