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. rollbacksql = "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.hqwc.cn/news/599398.html

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

相关文章

YOLOV8 + 双目测距

YOLOV8 双目测距 1. 环境配置2. 测距流程和原理2.1 测距流程2.2 测距原理 3. 代码部分解析3.1 相机参数stereoconfig.py3.2 测距部分3.3 主代码yolov8-stereo.py 4. 实验结果4.1 测距4.2 测距跟踪4.3 测距跟踪分割4.4 视频展示 相关文章 1. YOLOv5双目测距&#xff08;python&…

qt环境搭建-镜像源安装Qt Creator(5.15.2)以及配置环境变量

前言&#xff1a; 版本&#xff1a;5.15.2 镜像源&#xff1a;ustc与清华 纯小白&#xff0c;找了半天的镜像源安装qtcreator&#xff0c;搞了半天结果安装的是最新的&#xff0c;太新的对小白很不友好&#xff0c;bug比较多&#xff0c;支持的系统也不全&#xff0c;口碑不…

华为海思2024春招数字芯片岗机试题(共9套)

huawei海思2024春招数字芯片岗机试题(共9套&#xff09;&#xff08;WX:didadidadidida313&#xff0c;加我备注&#xff1a;CSDN huawei数字题目&#xff0c;谢绝白嫖哈&#xff09; 题目包含数字集成电路、System Verilog、Verilog2001、半导体制造技术、高级ASIC芯片综合、…

Python | Leetcode Python题解之第15题三数之和

题目&#xff1a; 题解&#xff1a; class Solution:def threeSum(self, nums: List[int]) -> List[List[int]]:n len(nums)nums.sort()ans list()# 枚举 afor first in range(n):# 需要和上一次枚举的数不相同if first > 0 and nums[first] nums[first - 1]:continu…

开启Java之旅——用Java实现简易的图书管理系统(24.4.7)

图书管理系统 一、设计思路 1、首先需要区分两类人&#xff0c;图书管理员和借书用户&#xff0c;不同的用户要展现不同的界面&#xff0c;利用继承和多态可以将其实现。 2、要将不同的操作封装起来&#xff0c;单独设计成为一个类&#xff0c;为了规范实现&#xff0c;需要…

解决前端精度丢失问题:后端Long类型到前端的处理策略

在Web开发中&#xff0c;我们经常遇到前后端数据类型不匹配的问题&#xff0c;特别是当后端使用大数据类型如Long时&#xff0c;前端由于JavaScript的数字精度限制&#xff0c;可能导致精度丢失。本文将深入探讨这个问题&#xff0c;并提供两种有效的解决方法。 一、问题背景 …

汇编基础----mov基本操作

汇编基础----mov基本操作 下载VS2022 这个网上教程很多,自行下载安装即可 新建项目 选择空项目,如何点击下一步 在源文件下创建这二个文件 修改配置使asm文件能被解析,右击项目名(demo)->生成依赖项->生成自定义->勾选如下图所示选项->确定 立即数寻址 main…

Linux--APP打开的文件在内核中如何表示

当用户在程序中使用了glibc库提供的文件操作函数open&#xff08;&#xff09;、read&#xff08;&#xff09;等访问文件时&#xff0c;这些函数会调用相应的系统调用来实际执行文件操作&#xff0c;并返回一个整数即文件句柄&#xff0c;文件句柄实际上是对应的 struct file …

PHP 中的 $2y$10,PHP 字符串加密函数 password_hash

PHP 用户密码加密函数 password_hash 自PHP5.5.0之后&#xff0c;新增加了密码散列算法函数(password_hash)&#xff0c;password_hash() 使用足够强度的单向散列算法创建密码的散列 Hash。 password_hash() 兼容 crypt()。 所以&#xff0c; crypt() 创建的密码散列也可用于 …

畅捷通TPlus 存在KeyInfoList.aspx SQL注入漏洞

声明&#xff1a; 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 简介 畅捷通T专属云适用于需要一体化管理的企业&#xf…

Python+Vuecil笔记

Nginx 进入目录: C:\nginx-1.20.2\nginx-1.20.2 start nginx 开始 nginx -s stop 停止 nginx -s quit 退出CSS 通过标签去写css 循环展示数据 JS 点击时执行事件 Django 配置media 在seetings里面修改 STATIC_URL /static/ MEDIA_URL /upload/ MEDIA_ROOT os.pat…

基于微信小程序的亿家旺生鲜云订单零售系统的设计与实现(论文+源码)_kaic

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了亿家旺生鲜云订单零售系统的开发全过程。通过分析亿家旺生鲜云订单零售系统管理的不足&#xff0c;创建了一个计算机管理亿家旺生鲜云订单零售系统的方案。文章介…