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

news2025/2/24 2:11:27
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;
}

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

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

相关文章

uniapp使用npm命令引入font-awesome图标库最新版本并解决APP和小程序不显示图标的问题

uniapp使用npm命令引入font-awesome图标库最新版本 图标库网址&#xff1a;https://fontawesome.com/search?qtools&or 命令行&#xff1a; 引入 npm i fortawesome/fontawesome-free 查看版本 npm list fortawesome在main.js文件中&#xff1a; import fortawesome/fo…

AI智能涂抹修补解决方案助力企业高效创作

传统的手动涂抹修补方式不仅效率低下&#xff0c;而且往往难以达到理想的视觉效果。美摄科技凭借深厚的AI技术研发实力&#xff0c;推出了面向企业的AI智能涂抹修补解决方案&#xff0c;为企业带来前所未有的创作体验。 美摄科技的AI智能涂抹修补解决方案&#xff0c;具备强大…

绝地求生:在小小的花园里面挖呀挖呀挖~ 29.1版本将支持可破坏地形功能

嗨&#xff0c;我是闲游盒~ 想必大家也都知道了新版本即将上线的可破坏地形功能即将在29.1版本上线&#xff0c;而具体的玩法暂时没有公布~ ◆ 随着离4月10日越来越近&#xff0c;官方发布了一条关于新版本可破坏地形的玩法预告 注意看&#xff0c;这个男人叫小帅&#xff0c;正…

基于小程序+ssm实现的悬赏信息发布系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;ssm 【…

Django项目定时任务django-crontab

首先定义一个定时任务函数tasks.py&#xff08;见文章末尾示例&#xff09;&#xff0c;编写函数&#xff0c;然后在setting.py中配置定时任务 1、首先安装django-crontab pip install django-crontab 2、在setting.py中添加应用 (在所有自定义注册app之上) INSTALLED_APPS …

C++ //练习 11.28 对一个string到int的vector的map,定义并初始化一个变量来保存在其上调用find所返回的结果。

C Primer&#xff08;第5版&#xff09; 练习 11.28 练习 11.28 对一个string到int的vector的map&#xff0c;定义并初始化一个变量来保存在其上调用find所返回的结果。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 /******…

书生·浦语训练营二期第三次笔记-茴香豆:搭建你的 RAG 智能助理

RAG学习文档1&#xff1a; https://paragshah.medium.com/unlock-the-power-of-your-knowledge-base-with-openai-gpt-apis-db9a1138cac4 RAG学习文档2: https://blog.demir.io/hands-on-with-rag-step-by-step-guide-to-integrating-retrieval-augmented-generation-in-llms-a…

Adobe InDesign 2024 v19.3 (macOS, Windows) - 版面设计和桌面出版软件

Adobe InDesign 2024 v19.3 (macOS, Windows) - 版面设计和桌面出版软件 Acrobat、After Effects、Animate、Audition、Bridge、Character Animator、Dimension、Dreamweaver、Illustrator、InCopy、InDesign、Lightroom Classic、Media Encoder、Photoshop、Premiere Pro、Ad…

Spring 如何优雅的灵活的Http重试

1、背景说明 在互联网时代&#xff0c; 不同系统之间大多数是通过http调用&#xff0c;调用过程中会超时、异常等过种问题。为了保证业务稳定&#xff0c;http 重试是常用方案。下面列举几种方案。 2、Http重试方案介绍 2.1 传统方案 1、使用传统的递归调用&#xff0c;实现方…

42.基于SpringBoot + Vue实现的前后端分离-服装销售平台管理系统(项目 + 论文)

项目介绍 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的交换和信息流通显得特别重要。因此&#xff0c;开发合适的服装销售平台成为企业必然要走的一步棋。开发合适的服…

让H5页面轻松打开第三方App,Xinstall助力实现无缝跳转

在移动互联网时代&#xff0c;H5页面因其跨平台、易传播的特性而被广泛应用&#xff0c;然而H5页面在打开第三方App时往往存在诸多不便。用户需要通过复杂的操作步骤才能实现跳转&#xff0c;这无疑降低了用户体验。为了解决这一难题&#xff0c;Xinstall应运而生&#xff0c;为…

达梦备份与恢复

达梦备份与恢复 基础环境 操作系统&#xff1a;Red Hat Enterprise Linux Server release 7.9 (Maipo) 数据库版本&#xff1a;DM Database Server 64 V8 架构&#xff1a;单实例1 设置bak_path路径 --创建备份文件存放目录 su - dmdba mkdir -p /dm8/backup--修改dm.ini 文件…

【面试题】RocketMQ的工作流程?

RocketMQ是一种开源的分布式消息队列系统&#xff0c;它具有高吞吐量、低延迟和高可靠性的特点。下面是RocketMQ的简要工作流程&#xff1a; Producer&#xff08;生产者&#xff09;发送消息&#xff1a;消息的生产者将消息发送到RocketMQ。生产者将消息封装为一个消息对象&am…

DIY自己的AI

一、开源AI大语言模型 目前开源的AI大语言模型(LLM)已经非常的多了&#xff0c;以下是收集的一些LLM&#xff1a; LLaMA LLaMA&#xff08;Large Language Model Meta AI&#xff09;&#xff1a;LLaMA是由MetaAI的Facebook人工智能实验室&#xff08;FAIR&#xff09;发布的…

html5分步问卷调查表模板源码

文章目录 1.设计来源1.1 问卷调查11.2 问卷调查21.3 问卷调查31.4 问卷调查41.5 问卷调查51.6 问卷调查6 2.效果和源码2.1 完整效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/137454703 html5分…

2024/4/1—力扣—连续数列

代码实现&#xff1a; 思路&#xff1a;最大子数组和 解法一&#xff1a;动态规划 #define max(a, b) ((a) > (b) ? (a) : (b))int maxSubArray(int* nums, int numsSize) {if (numsSize 0) { // 特殊情况return 0;}int dp[numsSize];dp[0] nums[0];int result dp[0];fo…

【动态规划-状态压缩dp】【蓝桥杯备考训练】:毕业旅行问题、蒙德里安的梦想、最短Hamilton路径、国际象棋、小国王【已更新完成】

目录 1、毕业旅行问题&#xff08;今日头条2019笔试题&#xff09; 2、蒙德里安的梦想&#xff08;算法竞赛进阶指南&#xff09; 3、最短Hamilton路径&#xff08;《算法竞赛进阶指南》&模板&#xff09; 4、国际象棋&#xff08;第十二届蓝桥杯省赛第二场C A组/B组&#…

MySQL的基本查询

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;MySQL &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容介绍了mysql的基本查询部分的知识&#xff0c;包括Crea…

日期时间相关的类

分界线jdk8 jdk8之前和之后分别提供了一些日期和时间的类&#xff0c;推荐使用jdk8之后的日期和时间类 Date类型 这是一个jdk8之前的类型&#xff0c;其中有很多方法已经过时了&#xff0c;选取了一些没有过时的API //jdk1.8之前的日期 Date Date date new Date(); // 从1970年…

多输入多输出 | Matlab实现OOA-BP鱼鹰算法优化BP神经网络多输入多输出预测

多输入多输出 | Matlab实现OOA-BP鱼鹰算法优化BP神经网络多输入多输出预测 目录 多输入多输出 | Matlab实现OOA-BP鱼鹰算法优化BP神经网络多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 多输入多输出 | Matlab实现OOA-BP鱼鹰算法优化BP神经网络…