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

news2024/11/25 13:42:48

    • 一、创建驱动程序实例
    • 二、连接服务器
      • 为什么使用`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.coloradmin.cn/o/1713194.html

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

相关文章

【网络安全】新的恶意软件:无文件恶意软件GhostHook正在广泛传播

文章目录 推荐阅读 一种新的恶意软件 GhostHook v1.0 正在一个网络犯罪论坛上迅速传播。这种创新的无文件浏览器恶意软件由 Native-One 黑客组织开发&#xff0c;具有独特的分发方式和多功能性&#xff0c;对各种平台和浏览器构成重大威胁。 GhostHook v1.0 支持 Windows、Andr…

一个交易者的自白:念念不忘的交易,10个日内9个亏

一、新手: 面对爆仓,我像个白痴 我是在2012年开始接触的&#xff0c;这些年里我尝到了残酷失败的滋味&#xff0c;更品尝过胜利带来的喜悦。刚刚接触时很自信&#xff0c;总想着自己有一天一定会变成千万富翁的&#xff0c;用杠杆获取暴利。 在我首次爆仓的时候&#xff0c;我的…

QT6.2.4 MSVC2019 连接MySql数据库,无驱动问题

1.下载 查询一下数据库驱动 qDebug()<<QSqlDatabase::drivers(); 结果显示&#xff0c;没有QMYSQL的驱动。 QList("QSQLITE", "QMARIADB", "QODBC", "QPSQL") MySql6.2.4驱动下载地址&#xff0c;如果是别的版本&#xff0c;…

使用Python构建CART决策树回归模型

数据预处理 此次构建模型是根据泰坦迪克号邮轮票价、乘客性别、船上亲友数量等特征信息来预测乘客存活率的模型&#xff0c;使用的数据集为泰坦尼克数据集&#xff0c;下载地址&#xff1a;taitanic | Kaggle。 在下载完数据集后&#xff0c;可以先试用 ydata_profiling库&am…

Codeforces Round 946 (Div. 3) A~G

A.Phone Desktop (枚举) 题意&#xff1a; 小 A A A的手机有一个桌面&#xff08;或称启动器&#xff09;。桌面可以由多个屏幕组成。每个屏幕表示为大小为 5 3 5 \times 3 53 的网格&#xff0c;即五行三列。 有 x x x 个应用程序的图标大小为 1 1 1 \times 1 11 个单…

高铁Wifi是如何接入的?

使用PC端的朋友&#xff0c;请将页面缩小到最小比例&#xff0c;阅读最佳&#xff01; 在飞驰的高铁上&#xff0c;除了窗外一闪而过的风景&#xff0c;你是否好奇过&#xff0c;高铁Wifi信号如何连接的呢&#xff1f; 远动的火车可不能连接光纤吧&#xff0c;难道是连接的卫星…

6.2 Go 切片(Slice)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

OrangePi AIpro初体验:开启嵌入式开发之旅

概述 随着物联网和智能设备时代的到来&#xff0c;单板电脑因其独特的优势成为创新项目和教育实践的重要工具。在众多单板电脑中&#xff0c;香橙派以其出色的性能和亲民的价格&#xff0c;十分吸引博主这初涉嵌入式开发的新手。博主有幸被CSDN邀请对OrangePi AIpro进行测评。…

Anaconda虚拟环境安装Pybullet

Anaconda虚拟环境安装Pybullet 当直接使用pip install Pybullet的时候出现以下问题&#xff1a; 查看报错信息和CSDN上的许多博客教程&#xff0c;基本都在说与缺少C的依赖有关需要安装几个G的microsoft visual 我尝试使用Conda 包管理器从 conda-forge 通道安装名为 pybulle…

PyTorch自定义张量操作开发指南【CFFI+CUDA】

PyTorch 与 TensorFlow 一起成为深度学习研究人员和从业者的标准。虽然 PyTorch 在张量运算或深度学习层方面提供了多种选择&#xff0c;但一些专门的操作仍然需要手动实现。在运行时至关重要的情况下&#xff0c;应使用 C 或 CUDA 来完成此操作&#xff0c;以支持 CPU 和 GPU …

快团团供货大团长如何打印电子面单?

一、功能说明 快团团打单平台是目前唯一一个服务于快团团团长的打单发货工具&#xff0c;免费提供给团长使用。可帮助团长快速打印面单、分拣包裹、完成发货。 目前快团团打单平台已支持大批量打印快递单、自定义快递面单、自动发货、绑定拼多多电子面单账号等功能&#xff0c…

摸鱼大数据——Hive表操作——复杂类型

1、hvie的SerDe机制 其中ROW FORMAT是语法关键字&#xff0c;DELIMITED和SERDE二选其一。本次我们主要学习DELIMITED关键字相关知识点 如果使用delimited: 表示底层默认使用的Serde类:LazySimpleSerDe类来处理数据。 如果使用serde:表示指定其他的Serde类来处理数据,支持用户自…

香橙派AIpro开发板初体验

香橙派AIpro开发板初体验 一、引言 在当前的AI发展浪潮中&#xff0c;边缘计算逐渐成为了研究的热点。香橙派AIpro开发板作为一款基于昇腾AI技术的开发板&#xff0c;凭借其强大的算力和丰富的接口&#xff0c;为AI边缘计算提供了强大的支持。最近&#xff0c;我也是拿到了官…

揭秘SQL中的公用表表达式:数据查询的新宠儿

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 揭秘SQL中的公用表表达式&#xff1a;数据查询的新宠儿 前言公用表表述的概述非递归CTE的作用递归CTE的作用CTE性能优化 前言 你是否曾经为SQL查询的复杂性而困扰不已&#xff1f;尤其是那些读写层子…

数据结构(一)顺序表

目录 一、概念&#xff08;一&#xff09;数据结构的三元素1. 逻辑结构&#xff08;1&#xff09;线性结构&#xff08;2&#xff09;非线性结构 2. 存储结构&#xff08;1&#xff09;顺序存储&#xff08;2&#xff09;链式存储&#xff08;3&#xff09;索引存储 3. 运算 &a…

douyin-vue:使用Vue3、Pinia和Vite5打造高度还原的抖音仿制项目

一&#xff1a;引言 在前端技术日新月异的今天&#xff0c;Vue.js作为一款流行的前端框架&#xff0c;不断吸引着开发者的目光。最近&#xff0c;GitHub上出现了一个备受瞩目的项目——douyin-vue&#xff0c;这是一个基于Vue3、Pinia和Vite5的移动端短视频项目&#xff0c;旨…

CCF20220301——未初始化警告

CCF20220301——未初始化警告 代码如下&#xff1a; #include<bits/stdc.h> using namespace std; #define Max 100000 int x[Max]{0},y[Max]{0}; int main() {int n,k;int cnt1,flag0;cin>>n>>k;for(int i1;i<k;i)cin>>x[i]>>y[i];for(in…

Linux命令 jps(Java Process Status)解释

文章目录 1、第一种解释2、第二种解释3、第三种解释 1、第一种解释 jps 命令本身并不是一个标准的 Unix/Linux 命令&#xff0c;但您可能是想提到 jps 的一个变种或误写了 jps 为 jps&#xff0c;而实际上可能是想提及 jps&#xff08;Java Virtual Machine Process Status To…

虚拟化概述

虚拟存储器(Virtual Memory) 它的基本思想是对于一个程序来说,它的程序(code)、数据(data)和堆栈(stack)的总大小可以超过实际物理内存的大小&#xff1b;操作系统把当前使用的部分内容放到物理内存中&#xff0c;而把其他未使用的内容放到更下一级存储器&#xff0c;如硬盘&a…

通过 coze 快速构建自己的智能体机器人

通过 coze 快速构建自己的智能体机器人 coze 的使用 一&#xff09;coze 是什么 「Coze 扣子」AI Bot 开发平台。任何用户都可以快速、低门槛地搭建自己的 Chatbot&#xff0c;且平台支持用户将其一键发布到飞书、微信公众号、豆包等渠道。 二&#xff09;coze 怎么注册 1. …