C++:MySQL的事务概念与使用(四)

1、事务的概念
  • 定义:事务是构成单一逻辑工作单元的操作集合,要么完整的执行,要么完全不执行。无论发生何种情况,DBS必须保证事务能正确、完整的执行。

  • 性质:事务的四大ACID性质。

    • 原子性(Atomicity):一个事务对数据库的所有操作,是一个不可分割的工作单元。这些操作要么全部执行,要么全都不执行。既要么执行成功要么执行失败
    • 一致性(Consistency):一个事务独立执行的结果,应该保持数据库的一致性,既数据不会因事务的执行而遭受破坏
    • 隔离性(Isolation):在多个事务并发执行时,系统应该保证与这些事务先后单独执行时的结果一样,此时称事务打到了隔离性的要求。也就是在多个事务并发执行时,保证执行结果是正确的,如同单用户环境一样。早些年的MyISAM数据库引擎是采用表锁的形式,当执行SQL语句时锁定一张表,而当今的InnoDB引擎是采用行锁定的,在操纵数据库的的时候只锁定操作的行不锁定这张表,这就是隔离性
    • 持久性(Durability):一个事务一旦完成全部操作后,它对数据库的所有更新应永久的反映在数据库中,不会丢失、即以后系统发生故障也是如此。
2、事务的并发读和隔离级别问题
2.1、事务的并发读问题
  • 脏读:一个事务读取到了另一个事务未成功提交的数据;例如:事务A对数据库中的数据进行了修改但是还未提交、此时事务B进行数据读取;但是事务A因为某些原因回滚了,此时B拿到的数据是一个无效数据,也叫脏数据!
  1. 不可重复读:同一个事务内,先后两次读取数据返回结果不一致;例如:事务A第一次读取到数据、事务B修改数据并且成功提交、事务A第二次读取数据;两次读取数据结果不一致。由于事务没有形成隔离导致

  2. 幻读:一个事务读取到另一个事务已经提交的添加或者删除的数据;例如:A事务读取数据、B事务删除(增加)数据,A事务再次读取数据,发现多出一些新的数据,像出现了幻觉一样。

  3. 幻读与不可重复度的区别:不可重复度强调的是修改数据;幻读强调的是添加、删除数据。

  4. 总结:脏读是致命的操作,因为拿到的数据是无效数据;而不可重复度与幻读是一种现象,只是先后读取不一致的问题,但是数据是有效的(其他事物成功提交)!

2.2、事务的隔离级别
  • TRANSACTION_NONE:无事务。

  • TRANSACTION_READ_UNCOMMITTED:未解决任何问题,可能出现一系列并发问题

  • TRANSACTION_READ_COMMITTED:解决了脏读问题

  • TRANSACTION_REPEATABLE_READ:解决了脏读和不可重复读问题

TRANSACTION_SERIALIZABLE:解决了脏读、不可重复读、幻读问题,采用串行化访问。
在这里插入图片描述

3、C++使用MySQL事务操作
3.1、事务的测试
  • 事务操作主要分4-5个步骤
    • 开启事务:“start transaction”
    • 关闭自动提交:“set autocommit = 0;”
    • 执行SQL语句:主要是一些增删改操作
    • 回滚或提交:当出现问题时可以rollback回滚,如果没有问题直接commit提交
    • 恢复自动提交:“set autocommit = 1;”
void transaction_test(MYSQL &mysql)
{
    /*
     * 事务的操作:
     * 1. 开启事务
     * 2. 关闭自动提交,开启手动提交
     * 3. 执行sql
     * 4. 成功 commit 或者 rollback
     * 5. 开启自动提交
     */
    // 1. 开启事务
    string sql = "start transaction;";
    mysql_real_query(&mysql, sql.c_str(), sql.length());

    // 2. 开启手动提交
    sql = "set autocommit = 0;";
    mysql_real_query(&mysql, sql.c_str(), sql.length());

    // 3. 执行sql语句
    for(int i = 1;i <= 5;i++){
        stringstream ss;
        sql = "insert into `test`(`username`, `password`) values('Admin', '123456');";
        int insert_result = mysql_real_query(&mysql, sql.c_str(), sql.length());
        if(insert_result != 0){
            cout << "insert data failed! sql = " << sql << ", error msg = " << mysql_error(&mysql) << endl;
        }
    }

    // 4. rollback
    sql = "rollback";
    mysql_real_query(&mysql, sql.c_str(), sql.length());

    // 5. 再次执行插入操作
    sql = "insert into `test`(`username`, `password`) values('Splay', '123456');";
    mysql_real_query(&mysql, sql.c_str(), sql.length());

    // 6. commit提交
    sql = "commit";
    mysql_real_query(&mysql, sql.c_str(), sql.length());


    // 7. 回复自动提交
    sql = "set autocommit = 1;";
    mysql_real_query(&mysql, sql.c_str(), sql.length());

    // 8. 查询数据库数据的数量
    sql = "select count(*) from `test`;";
    mysql_real_query(&mysql, sql.c_str(), sql.length());
    // 释放mysql结构体
    MYSQL_RES* result = mysql_store_result(&mysql);
    cout << "当前数据库的数据行数:" << mysql_fetch_row(result)[0] << endl;
}
3.2、事务与不同批量插入数据的性能对比

对于不同的类型的操作每次都插入1000条数据,在插入之前将表清空。

  • 单条插入:每次插入一条数据,这样就会导致一个问题执行一条SQL语句,频繁的开启关闭事务会造成性能浪费
  • 批量插入:1000条数据一次性组合,通过CLIENT_MULTI_STATEMENT设置进行多SQL的同时执行
  • 事务插入:将1000条数据打包成一个事务里,最后一次性提交(一个事务内)
void truncate_table(MYSQL &mysql)
{
    string sql = "truncate table `test`;";
    mysql_real_query(&mysql, sql.c_str(), sql.length());
}

void test_single_insert(MYSQL &mysql)
{
    truncate_table(mysql);
    auto start = std::chrono::system_clock::now();
    for(int i = 1;i <= 1000;i++){
        string sql = "insert into `test`(`username`, `password`) values('Splay', '123456');";
        mysql_real_query(&mysql, sql.c_str(), sql.length());
    }
    auto end = std::chrono::system_clock::now();
    auto duration = duration_cast<chrono::milliseconds> (end - start);
    cout << "single_insert插入1万条数据所需的时间: " << duration.count()/1000.0 << "秒" << endl;
}

void test_multi_insert(MYSQL &mysql)
{
    truncate_table(mysql);
    auto start = std::chrono::system_clock::now();
    string sql = "";
    for(int i = 1;i <= 1000;i++){
        sql += "insert into `test`(`username`, `password`) values('Splay', '123456');";
    }
    mysql_real_query(&mysql, sql.c_str(), sql.length());
    do{
        mysql_affected_rows(&mysql);
    } while(mysql_next_result(&mysql) == 0);
    auto end = std::chrono::system_clock::now();
    auto duration = duration_cast<chrono::milliseconds> (end - start);
    cout << "multi_insert插入1万条数据所需的时间: " << duration.count()/1000.0 << "秒" << endl;
}


void test_transaction_insert(MYSQL &mysql)
{
    truncate_table(mysql);
    auto start = std::chrono::system_clock::now();
    // 1. 开启事务
    string sql = "start transaction;";
    mysql_real_query(&mysql, sql.c_str(), sql.length());

    // 2. 开启手动提交
    sql = "set autocommit = 0;";
    mysql_real_query(&mysql, sql.c_str(), sql.length());

    // 3. 执行sql语句
    for(int i = 1;i <= 1000;i++){
        sql = "insert into `test`(`username`, `password`) values('Admin', '123456');";
        mysql_real_query(&mysql, sql.c_str(), sql.length());
    }

    // 4. commit提交
    sql = "commit";
    mysql_real_query(&mysql, sql.c_str(), sql.length());

    // 5. 恢复自动提交
    sql = "set autocommit = 1;";
    mysql_real_query(&mysql, sql.c_str(), sql.length());
    auto end = std::chrono::system_clock::now();
    auto duration = duration_cast<chrono::milliseconds> (end - start);
    cout << "transaction_insert插入1万条数据所需的时间: " << duration.count()/1000.0 << "秒" << endl;
}

// mysql connect 127.0.0.1 success!
// single_insert插入1万条数据所需的时间: 5.379秒
// multi_insert插入1万条数据所需的时间: 5.516秒
// transaction_insert插入1万条数据所需的时间: 0.068秒
3.3、连接等其他代码
#include <iostream>
#include <mysql/mysql.h>
#include <cstring>
#include <sstream>
#include <string>
#include <chrono>
#include <unordered_map>
using namespace std;
using namespace chrono;


void create_table(MYSQL &mysql)
{
    string sql = "CREATE TABLE IF NOT EXISTS `test` (\
                   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,\
                   `username` varchar(255) NOT NULL,\
                   `password` varchar(255) NOT NULL,\
                   PRIMARY KEY (`id`)\
                  ) ENGINE=InnoDB DEFAULT CHARSET=utf8;";
    if(mysql_real_query(&mysql, sql.c_str(), sql.length()) != 0){
        cout << "mysql_query failed!" << endl;
    }
}

int main(int argc, char *argv[])
{
    MYSQL mysql;
    // 初始化mysql结构体并且初始化服务连接环境
    mysql_init(&mysql);
    const char *host = "127.0.0.1";
    const char *user = "root";
    const char *password = "123456";
    const char *db = "cpp";
    int timeout = 3;
    // 连接超时时长设置
    mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);

    // 断开重连设置
    int reconnect = 1;
    mysql_options(&mysql, MYSQL_OPT_RECONNECT, &reconnect);

    // MySQL连接建立
    if(!mysql_real_connect(&mysql, host, user, password, db, 3306, 0, CLIENT_MULTI_STATEMENTS)){
        std::cout << "mysql connect failed!" << mysql_error(&mysql) << std::endl;
    }
    else{
        std::cout << "mysql connect " << host << " success!" << std::endl;
    }
//    create_table(mysql);
//    transaction_test(mysql);

    test_single_insert(mysql);

    test_multi_insert(mysql);

    test_transaction_insert(mysql);

    mysql_close(&mysql);
    mysql_library_end();
    return 0;
}

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

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

相关文章

基于SpringBoot的“汽车租赁系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“汽车租赁系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 管理员登录界面图 管理员功能界面…

AWE2024酷开科技智能家居,让生活从此更智能!

随着科技的飞速发展&#xff0c;智能家居已经成为了人们生活中不可或缺的一部分。在这个领域里&#xff0c;酷开科技品类逐渐丰富&#xff0c;在AWE2024展会上展现出耀眼光芒&#xff0c;将全品类智能家电新品集结亮相&#xff01;让人们的生活更加便捷、舒适和智能化。 酷开K…

MUX VLAN

目录 原理概述 实验目的 实验内容 实验拓扑 1.基本配置 2.使用Hybrid端口实现网络需求 3.使用Mux VLAN实现网络需求 原理概述 在实际的企业网络环境中&#xff0c;往往需要所有的终端用户都能够访问某些特定的服务器&#xff0c;而用户之间的访问控制规则则比较复杂。在…

基于Spring Boot+Vue的在线拍卖系统

随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单管理、…

dockerhub右键快速搜索脚本

Chrome 浏览器扩展的后台脚本&#xff0c;用于创建右键菜单项&#xff0c;并根据用户的操作在新的标签页中打开 Docker Hub 网站或者进行搜索。 // 创建右键菜单项&#xff0c;用于打开 Docker Hub 网站 chrome.contextMenus.create({id: search-home, // 菜单项的唯一标识符t…

BMP280芯片I2C驱动开发指南

这颗芯片不太容易焊接&#xff0c;不能长时间风枪吹&#xff0c;否则容易掉壳。 第一部分 硬件连接 电路很简单&#xff0c;没什么需要注意的。 第二部分 软件驱动 本来打算使用SPL06的&#xff0c;结果焊接掉壳了&#xff0c;更换成bmp280了。函数名没有变过来。。。 void …

node相关

文章目录 nodeJS是什么&#xff1f;优缺点使用场景全局对象适合用于构建 I/O 密集型不适用于计算密集型任务 nodeJS是什么&#xff1f; Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境&#xff0c;它是跨平台和开源的。 Node.js 使用高效、轻量级的事件驱动、非阻…

免费SSL通配符证书/SSL泛域名证书获取教程

我们先基本了解什么是SSL证书以及其作用。SSL证书是一种数字证书&#xff0c;它通过为网站提供身份验证和数据加密服务&#xff0c;从而保护网站的用户信息安全。当我们在浏览器的地址栏看到“https”和绿色锁标志时&#xff0c;就表示该网站使用了SSL证书。 那么什么又是通配…

ES入门十四:分词器

我们存储到ES中数据大致分为以下两种&#xff1a; 全文本&#xff0c;例如文章内容、通知内容精确值&#xff0c;如实体Id 在对这两类值进行查询的时候&#xff0c;精确值类型会比较它们的二进制&#xff0c;其结果只有相等或者不想等。而对全文本类型进行等值比较是不太实现…

适用于 Windows 10 的 10 大免费数据恢复软件

数据丢失可能是一场噩梦&#xff0c;尤其是在涉及重要文件和文档时。无论是由于意外删除、系统崩溃还是病毒攻击&#xff0c;找到适合 Windows 10 的文件夹恢复软件都可以在恢复丢失的数据方面发挥重要作用。在本指南中&#xff0c;我们将探索适用于 Windows 10 用户的 10 大免…

【数字IC/FPGA】什么是无符号数?什么是有符号数?

进制 虽然在日常生活中&#xff0c;我们已经习惯了使用10进制数字&#xff0c;但在由数字电路构成的数字世界中&#xff0c;2进制才是效率更高的选择。 10进制与2进制 10进制&#xff08;decimal&#xff09;计数法&#xff08;一般也叫阿拉伯计数法&#xff09;是在日常生活…

优优嗨聚集团:个人债务,危险的边缘舞者

在现代社会&#xff0c;个人债务已成为一个不容忽视的现象。随着消费水平的提高和信贷市场的繁荣&#xff0c;越来越多的人选择通过借贷来满足生活或投资的需求。然而&#xff0c;个人债务如同一把双刃剑&#xff0c;既能助力我们实现梦想&#xff0c;也可能让我们陷入困境。那…

SiteServer 学习笔记 Day06 添加栏目名称

1、在关于我们栏目中添加ISO认证和系统、质量声明、以客户为中心。 2、在市场服务栏目中添加电信和网络、医疗系统、清洁技术、计算和存储。 3、在制造服务拉姆中添加PCB组装、塑料成型服务、机器制造。 4、在测试服务栏目中添加测试开发、功能测试。 5、在工程服务栏目中添…

PTA(题目集二 题目 代码 C++)

目录 题目一&#xff1a; 代码&#xff1a; 题目二&#xff1a; 代码&#xff1a; 题目三&#xff1a; 代码&#xff1a; 题目四&#xff1a; 代码&#xff1a; 题目五&#xff1a; 代码&#xff1a; 题目六&#xff1a; 代码&#xff1a; 题目七&#xff1a; 代…

《从零开始学架构》读书笔记(一)

目录 软件架构设计产生的历史背景 软件架构设计的目的 系统复杂度来源 追求高性能 一、单机高性能 二、集群的高性能 追求高可用 一、计算高可用 二、存储高可用 追求可扩展性 一、预测变化 二、应对变化 追求安全、低成本、规模 一、安全 二、低成本 三、规模…

使用 Python 的 LSTM 进行股市预测

目录 一、说明 二、为什么需要时间序列模型&#xff1f; 三、下载数据 3.1 从 Alphavantage 获取数据 3.1 从 Kaggle 获取数据 3.3 数据探索 3.4 数据可视化 四、将数据拆分为训练集和测试集 五、数据标准化 六、通过平均进行一步预测 6.1 标准平均值 6.2 指数移动平均线 6.3 如…

C++类与对象中(个人笔记)

类与对象中 类的6个默认成员函数1.构造函数1.1特性 2.析构函数2.1特性 3.拷贝构造函数3.1特性 4.赋值运算符重载4.1特性 5.日期类的实现6.const成员6.1const成员的几个问题 7.取地址及const取地址操作符重载 类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为…

iOS 17.5系统或可识别并禁用未知跟踪器,苹果Find My技术应用越来越合理

苹果公司去年与谷歌合作&#xff0c;宣布将制定新的行业标准来解决人们日益关注的跟踪器隐私问题。苹果计划在即将发布的 iOS 17.5 系统中加入这项提升用户隐私保护的新功能。 科技网站 9to5Mac 在苹果发布的 iOS 17.5 开发者测试版内部代码中发现了这项反跟踪功能的蛛丝马迹…

SAP HCM PT 2003修改班次,PP61无法自动更新

今天遇到一个问题&#xff0c;2003修改班次以后PP61无法自动更新&#xff0c;开始一直以为是什么配置点漏掉&#xff0c;但是发现开发机没问题&#xff0c;后来发现是用户选保存的时候选中目标计划的完成&#xff0c;这个是保存到实际计划的&#xff0c;数据存储psoll中&#x…

引入精益管理方式,需要提前做到这九点

​ 近年来&#xff0c;软件项目的规模及其复杂性正在以空前的速度增长&#xff0c;互联网用户市场庞大&#xff0c;互联网公司和相应的软件产品层出不穷。快速响应需求变化往往是互联网行业的常态&#xff0c;软件产品的快速开发迭代对于公司迅速占领市场、抢占商机有着举足轻重…