当前位置: 首页 > news >正文

【server组件】——mysql连接池的实现原理

目录

1.池化技术

2.数据库连接池的定义

3.为什么要使用连接池

4. 数据库连接池的运行机制

5. 连接池与线程池的关系 

6. CResultSet的设计

 6.1构造函数

7. CDBConn的设计

6.1.构造函数 

6.2.init——初始化连接

8.数据库连接池的设计要点

9.接口设计

9.1 构造函数

9.2 请求获取连接 

9.3 释放连接

9.4 析构连接

9.5 mysql重连机制

10. 连接池数量设置

经验公式

实际分析

1.池化技术

池化技术能够 减少资源对象的创建次数提高程序的响应性能,特别是在 高并发下这种提高更加明显。 使用池化技术缓存的资源对象有如下共同特点:

1. 对象创建时间长;

2. 对象创建需要大量资源;

3. 对象创建后可被重复使用

像常见的 线程池、内存池、连接池、对象池 都具有以上的共同特点。

2.数据库连接池的定义

数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成 一个连接池,由程序 动态地对池中的连接进行 申请,使用,释放

3.为什么要使用连接池

1.资源的复用

由于 数据库 连接得到复用,避免了 频繁的创建、释放连接引起的性能开销,在减少系统消耗的基础 上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数 量)。

2.更快的响应速度

数据库连接池在初始化过程中,已经创建了若干数据库连接置于池中备用。对于业务请求处理而言,直接利用现有可用连接避免了从数据库连接初始化和释 放过程的开销,从而缩减了响应时间,提高了响应速度

3. 统一的连接管理,避免数据库连接泄露

在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而 避免了常规数据库连接操作中可能出现的资源泄露

4. 数据库连接池的运行机制

1. 从连接池获取或创建可用连接

2. 使用完毕之后,把连接返回给连接池

3. 在系统关闭前,断开所有连接并释放连接占用的系统资源

5. 连接池与线程池的关系 

当线程池中 某个线程 执行任务的时候 需要访问数据库的时候,需要从连接池中获取到空闲的连接,任务处理完毕后,线程 再将连接归还给连接池。

线程池与连接池的区别:

线程池:主动操作,主动获取任务并执行任务

连接池:被动操作,池的对象被任务获取,执行完任务后归还

6. CResultSet的设计

// 返回结果 select的时候用
class CResultSet {
public:CResultSet(MYSQL_RES* res);virtual ~CResultSet();bool Next();//获取下一行数据int GetInt(const char* key); //获取int类型的value值char* GetString(const char* key);//获取字符串类型的value值
private:int _GetIndex(const char* key);MYSQL_RES* 			m_res;MYSQL_ROW			m_row;map<string, int>	m_key_map;
};

 6.1构造函数


//将所有行数据存储到 m_row中,将字段名存储到 m_key_map,并记录其id
CResultSet::CResultSet(MYSQL_RES *res)
{m_res = res;// map table field key to index in the result arrayint num_fields = mysql_num_fields(m_res);MYSQL_FIELD *fields = mysql_fetch_fields(m_res);for (int i = 0; i < num_fields; i++){// 将表头数据存储到m_key_map中m_key_map.insert(make_pair(fields[i].name, i));}
}

根据字段名获取 下标 

int CResultSet::_GetIndex(const char *key)
{map<string, int>::iterator it = m_key_map.find(key);if (it == m_key_map.end()){return -1;}else{return it->second;}
}//根据key 获取 int 类型 value值
int CResultSet::GetInt(const char *key)
{int idx = _GetIndex(key);if (idx == -1){return 0;}else{return atoi(m_row[idx]); // 有索引}
}//根据 key值获取 字符串类型 value值
char *CResultSet::GetString(const char *key)
{int idx = _GetIndex(key);if (idx == -1){return NULL;}else{return m_row[idx];		// 列}
}//获取下一行数据
bool CResultSet::Next()
{m_row = mysql_fetch_row(m_res);if (m_row){return true;}else{return false;}
}

7. CDBConn的设计

CDBConn是一个 自主封装的 MySQL连接,从连接池中获取到的连接时一个CDBConn对象类型。

class CDBConn {
public:CDBConn(CDBPool* pDBPool);virtual ~CDBConn();int Init();// 创建表bool ExecuteCreate(const char* sql_query);// 删除表bool ExecuteDrop(const char* sql_query);// 查询CResultSet* ExecuteQuery(const char* sql_query);bool ExecuteUpdate(const char* sql_query, bool care_affected_rows = true);uint32_t GetInsertId();// 开启事务bool StartTransaction();// 提交事务bool Commit();// 回滚事务bool Rollback();// 获取连接池名const char* GetPoolName();MYSQL* GetMysql() { return m_mysql; }
private:CDBPool* 	m_pDBPool;	// to get MySQL server informationMYSQL* 		m_mysql;	// 对应一个连接
};

6.1.构造函数 

CDBConn::CDBConn(CDBPool *pPool)
{m_pDBPool = pPool;m_mysql = NULL;
}

6.2.init——初始化连接

int CDBConn::Init()
{m_mysql = mysql_init(NULL);	// mysql_标准的mysql c client对应的apiif (!m_mysql){log_error("mysql_init failed\n");return 1;}my_bool reconnect = true;mysql_options(m_mysql, MYSQL_OPT_RECONNECT, &reconnect);	// 配合mysql_ping实现自动重连mysql_options(m_mysql, MYSQL_SET_CHARSET_NAME, "utf8mb4");	// utf8mb4和utf8区别// ip 端口 用户名 密码 数据库名if (!mysql_real_connect(m_mysql, m_pDBPool->GetDBServerIP(), m_pDBPool->GetUsername(), m_pDBPool->GetPasswrod(),m_pDBPool->GetDBName(), m_pDBPool->GetDBServerPort(), NULL, 0)){log_error("mysql_real_connect failed: %s\n", mysql_error(m_mysql));return 2;}return 0;
}

8.数据库连接池的设计要点

连接池的设计思路:

1.连接到数据库,涉及到 数据库ip、端口、用户名、密码、数据库名字等;

  •  配置最小的连接数和 最大连接数

2.定义一个队列管理 连接

3.获取连接对象的 接口

4.归还连接对象的接口

5. 定义连接池的名称

class CDBPool {	// 只是负责管理连接CDBConn,真正干活的是CDBConn
public:CDBPool() {}CDBPool(const char* pool_name, const char* db_server_ip, uint16_t db_server_port,const char* username, const char* password, const char* db_name, int max_conn_cnt);virtual 	~CDBPool();int 		Init();		// 连接数据库,创建连接CDBConn* 	GetDBConn(const int timeout_ms = 0);	// 获取连接资源void 		RelDBConn(CDBConn* pConn);	// 归还连接资源const char* GetPoolName() { return m_pool_name.c_str(); }const char* GetDBServerIP() { return m_db_server_ip.c_str(); }uint16_t 	GetDBServerPort() { return m_db_server_port; }const char* GetUsername() { return m_username.c_str(); }const char* GetPasswrod() { return m_password.c_str(); }const char* GetDBName() { return m_db_name.c_str(); }
private:string 		m_pool_name;	// 连接池名称string 		m_db_server_ip;	// 数据库ipuint16_t	m_db_server_port; // 数据库端口string 		m_username;  	// 用户名string 		m_password;		// 用户密码string 		m_db_name;		// db名称int			m_db_cur_conn_cnt;	// 当前启用的连接数量int 		m_db_max_conn_cnt;	// 最大连接数量list<CDBConn*>	m_free_list;	// 空闲的连接list<CDBConn*>	m_used_list;		// 记录已经被请求的连接std::mutex m_mutex;std::condition_variable m_cond_var;bool m_abort_request = false;// CThreadNotify	m_free_notify;	// 信号量
};

9.接口设计

9.1 构造函数

CDBPool::CDBPool(const char *pool_name, const char *db_server_ip, uint16_t db_server_port,const char *username, const char *password, const char *db_name, int max_conn_cnt)
{m_pool_name = pool_name;m_db_server_ip = db_server_ip;m_db_server_port = db_server_port;m_username = username;m_password = password;m_db_name = db_name;m_db_max_conn_cnt = max_conn_cnt;	// m_db_cur_conn_cnt = MIN_DB_CONN_CNT; // 最小连接数量
}

9.2 Init 初始化

创建固定的最小的连接数,并将连接存放到 空闲队列中。


int CDBPool::Init()
{// 创建固定最小的连接数量for (int i = 0; i < m_db_cur_conn_cnt; i++){CDBConn *pDBConn = new CDBConn(this);int ret = pDBConn->Init();if (ret){delete pDBConn;return ret;}m_free_list.push_back(pDBConn);}// log_info("db pool: %s, size: %d\n", m_pool_name.c_str(), (int)m_free_list.size());return 0;
}

9.2 请求获取连接 

请连接流程

CDBConn *CDBPool::GetDBConn(const int timeout_ms)
{std::unique_lock<std::mutex> lock(m_mutex);//m_abort_request 判断连接池是否被终止if(m_abort_request) {log_warn("have aboort\n");return NULL;}if (m_free_list.empty())		// 当没有连接可以用时{// 第一步先检测 当前连接数量是否达到最大的连接数量 if (m_db_cur_conn_cnt >= m_db_max_conn_cnt){// 如果已经到达了,看看是否需要超时等待if(timeout_ms <= 0)		// 死等,直到有连接可以用 或者 连接池要退出{log_info("wait ms:%d\n", timeout_ms);m_cond_var.wait(lock, [this] {// log_info("wait:%d, size:%d\n", wait_cout++, m_free_list.size());// 当前连接数量小于最大连接数量 或者请求释放连接池时退出return (!m_free_list.empty()) | m_abort_request;});} else {// return如果返回 false,继续wait(或者超时),  如果返回true退出wait// 1.m_free_list不为空// 2.超时退出// 3. m_abort_request被置为true,要释放整个连接池m_cond_var.wait_for(lock, std::chrono::milliseconds(timeout_ms), [this] {// log_info("wait_for:%d, size:%d\n", wait_cout++, m_free_list.size());return (!m_free_list.empty()) | m_abort_request;});// 带超时功能时还要判断是否为空if(m_free_list.empty()) 	// 如果连接池还是没有空闲则退出{return NULL;}}if(m_abort_request) {log_warn("have aboort\n");return NULL;}}else // 还没有到最大连接则创建连接{CDBConn *pDBConn = new CDBConn(this);	//新建连接int ret = pDBConn->Init();if (ret){log_error("Init DBConnecton failed\n\n");delete pDBConn;return NULL;}else{m_free_list.push_back(pDBConn);m_db_cur_conn_cnt++;// log_info("new db connection: %s, conn_cnt: %d\n", m_pool_name.c_str(), m_db_cur_conn_cnt);}}}CDBConn *pConn = m_free_list.front();	// 获取连接m_free_list.pop_front();	// STL 吐出连接,从空闲队列删除m_used_list.push_back(pConn);//将连接存放到被使用的 链表中return pConn;
}

9.3 释放连接

void CDBPool::RelDBConn(CDBConn *pConn)
{std::lock_guard<std::mutex> lock(m_mutex);list<CDBConn *>::iterator it = m_free_list.begin();for (; it != m_free_list.end(); it++)	// 避免重复归还{if (*it == pConn)	{break;}}if (it == m_free_list.end()){m_used_list.remove(pConn);m_free_list.push_back(pConn);m_cond_var.notify_one();		// 通知取队列} else {log_error("RelDBConn failed\n");}
}

9.4 析构连接

CDBPool::~CDBPool()
{std::lock_guard<std::mutex> lock(m_mutex);m_abort_request = true;m_cond_var.notify_all();		// 通知所有在等待的线程for (list<CDBConn *>::iterator it = m_free_list.begin(); it != m_free_list.end(); it++){CDBConn *pConn = *it;delete pConn;}m_free_list.clear();
}

9.5 mysql重连机制

1.设置重连机制属性

  //1. 设置启用(当发现连接断开时的)自动重连, 配合mysql_ping实现自动重连   
my_bool reconnect = true;
mysql_options(m_mysql, MYSQL_OPT_RECONNECT, &reconnect);    

2. 检测连接是否正常

int STDCALL mysql_ping(MYSQL *mysql);

描述:

检查与服务端的连接是否正常。连接断开时,如果自动重新连接功能未被禁用,则尝试重新连接服务 器。该函数可被客户端用来检测闲置许久以后,与服务端的连接是否关闭,如有需要,则重新连接。

返回值:

连接正常,返回0;如有错误发生,则返回非0值。返回非0值并不意味着服务器本身关闭掉,也有可能 是网络原因导致网络不通。

10. 连接池数量设置

经验公式

连接数 = ((核心数 * 2) + 有效磁盘数)

按照这个公式,即是说你的服务器 CPU 是 4核 i7 的,那连接池连接数大小应该为 ((4*2)+1)=9

这里只是一个经验公式,还要和线程池数量以及业务结合在一起吗,根据经验公式的连接数的上下去测试连接池性能瓶颈。

实际分析

如果任务整体上是一个IO密集型的任务在处理一个请求的过程中(处理一个任务),总共耗时 100+5=105ms,而其中只有 5ms是用于计算操作的(消耗cpu),另外的100ms等待io响应,CPU利用 率为5/(100+5)。

使用线程池是为了尽量提高CPU的利用率,减少对CPU资源的浪费假设以100%的CPU利用率来说,要 达到100%的CPU利用率,对于一个CPU就要设置其利用率的倒数个数的线程数,也即 1/(5/(100+5))=21,4个CPU的话就乘以4。那么算下来的话,就是……84,这个时候线程池要设置84个线 程数,然后连接池的最大连接数量也是设置为84个连接

相关文章:

【server组件】——mysql连接池的实现原理

目录 1.池化技术 2.数据库连接池的定义 3.为什么要使用连接池 4. 数据库连接池的运行机制 5. 连接池与线程池的关系 6. CResultSet的设计 6.1构造函数 7. CDBConn的设计 6.1.构造函数 6.2.init——初始化连接 8.数据库连接池的设计要点 9.接口设计 9.1 构造函数 …...

DSP开发:串口sci的发送与接收实现

DSP开发&#xff1a;串口sci的发送与接收实现 文章目录 DSP开发&#xff1a;串口sci的发送与接收实现串口配置串口SCI初始化详细分析串口SCI使用 串口配置 /*--------------------------------------------scia----------------------------*/ /*----------------------------…...

实训一 :Linux的启动、关机及登录

实训一 &#xff1a;Linux的启动、关机及登录 2017 年 2 月 22 日 今日公布 实训目标 完成本次实训&#xff0c;将能够&#xff1a; 描述Linux的开机过程。在图形模式和文本模式下登录Linux。关闭和重启Linux 实训准备 一台已安装RHEL6的虚拟计算机&#xff0c;Linux虚拟…...

Redis分布式锁问题

1、业务单机情况下 问题&#xff1a;并发没有加锁导致线程安全问题。 解决方法&#xff1a;加锁处理&#xff0c;如lock、synchronized 仍有问题&#xff1a;业务分布式情况下&#xff0c;代码级别加锁已经无效。需要借助第三方组件&#xff0c;如redis、zookeeper。 2、业务分…...

windows安装apache-jmeter-5.6.2教程

目录 一、下载安装包&#xff08;推荐第二种&#xff09; 二、安装jmeter 三、启动jmeter 一、下载安装包&#xff08;推荐第二种&#xff09; 1.官网下载&#xff1a;Apache JMeter - Download Apache JMeter 2.百度云下载&#xff1a;链接&#xff1a;https://pan.baidu.…...

密码检查-C语言/Java

描述 小明同学最近开发了一个网站&#xff0c;在用户注册账户的时候&#xff0c;需要设置账户的密码&#xff0c;为了加强账户的安全性&#xff0c;小明对密码强度有一定要求&#xff1a; 1. 密码只能由大写字母&#xff0c;小写字母&#xff0c;数字构成&#xff1b; 2. 密码不…...

基于Matlab实现心电信号小波特征提取和对应疾病识别仿真(附上源码+数据集)

本文基于Matlab平台&#xff0c;研究了心电信号的小波特征提取方法&#xff0c;并应用于心电信号疾病识别仿真实验中。首先&#xff0c;介绍了心电信号的基本特征和常见的心电疾病。然后&#xff0c;详细阐述了小波变换的原理和方法&#xff0c;并提出了一种基于小波分解和小波…...

第五十二天

HTML5 ●MathML 是数学标记语言&#xff0c;是一种基于XML&#xff08;标准通用标记语言的子集&#xff09;的标准&#xff0c;用来在互联网上书写数学符号和公式的置标语言。 ●拖放 拖放是一种常见的特性&#xff0c;即抓取对象以后拖到另一个位置。 在 HTML5 中&#xf…...

爬虫练手项目——获取龙族小说全文

网站信息 目标网站信息如下&#xff1a;包含了龙族1-5全部内容 代码 import requests from bs4 import BeautifulSoup import os import timeheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Sa…...

OpenCV图像处理——几何变换

目录 图像缩放图像平移图像旋转图像的仿射变换透射变换图像金字塔 图像缩放 cv.resize(src,dsize,fx0,fy0,interpolationcv2.INTER_LINEAR)import numpy as np import cv2 as cv import matplotlib.pyplot as pltkidscv.imread(./汪学长的随堂资料/4/图像操作/dog.jpg) plt.im…...

Apache JMeter:完全指南

Apache JMeter 是一款开源的性能测试工具&#xff0c;可以用于测试 Web 应用程序、FTP 服务器、数据库等各种类型的服务器。本文将以 JMeter 5.5 为例介绍 JMeter 的使用方法。 下载和安装 由于 JMeter 是使用 Java 开发的&#xff0c;因此在运行之前必须先安装 JDK。您可以在…...

js obj 生成java 实体 entity

js obj 生成java 实体 entity D:\proj\js\js-util\gen_java.js 文档&#xff1a;js obj 生成java 实体 entity.note 链接&#xff1a;http://note.youdao.com/noteshare?idc61fbd4b8684dc41c8c9ab42107d5f87&subE7484F5F277041578A2E58FDC6320BA6 添加链接描述 class S…...

【第二阶段】kotlin语言的匿名函数与具名函数

fun main() {//匿名函数val niminginfoniming("kotlin",20,{"$it"})println(niminginfo)//具名函数 理解&#xff1a;showResult:(String)->String):StringshowResultImpl(result:String):Stringval juminginfoniming("c ",20,::showResultI…...

P1123 取数游戏

取数游戏 题目描述 一个 N M N\times M NM 的由非负整数构成的数字矩阵&#xff0c;你需要在其中取出若干个数字&#xff0c;使得取出的任意两个数字不相邻&#xff08;若一个数字在另外一个数字相邻 8 8 8 个格子中的一个即认为这两个数字相邻&#xff09;&#xff0c;求…...

JavaScript高级:原型与原型链继承方式

在 JavaScript 中&#xff0c;继承是一种重要的概念&#xff0c;它使得对象可以从其他对象继承属性和方法&#xff0c;实现代码的重用和扩展。原型与原型链是 JavaScript 中实现继承的核心机制&#xff0c;虽然听起来有些高深&#xff0c;但我们可以通过通俗易懂的方式来理解它…...

使用vue-grid-layout时 You may need an appropriate loader to handle this file type.

使用vue-grid-layout时 You may need an appropriate loader to handle this file type. node版本不匹配 我的node v14.16.0 vue-gride-layout 需要用 v 2.3.7的版本 卸载后重新安装即可...

C# 2048小游戏核心算法

文章目录 01.程序结构划分02.去零03.合并04.上移05.下移/左移/右移&#xff0c;只是取数据的方向不同06.提高可读性 01.程序结构划分 02.去零 有序向量“唯一化”的思路。 /// <summary>/// 去零/// </summary>/// <param name"row">对于一行或一…...

设计模式(5)代理模式

一、介绍&#xff1a; 【Subject/抽象角色】定义了RealSubject和Proxy的共用接口&#xff0c;这样就可以在任何使用RealSubject的地方都可以使用Proxy 【RealSubject/真实角色】定义Proxy所代表的真实实体 【Proxy/代理角色】保存一个引用使得代理可以访问实体&#xff0c;并…...

Django配置(部署环境较乱,暂时启用)

django配置 web服务器中部署项目及WSGI简介 web服务器 WSGI 在IIS中部署django项目 安装 wfastcgi &#xff1a;pip install wfastcgi安装IIS&#xff1a; 以上选择项勾选后确定 将CGI文件复制到项目中&#xff0c; 将项目复制到IIS默认目录中 部署IIS 添加变量信息如下…...

【设计模式】桥接模式

桥接&#xff08;Bridge&#xff09;是用于把抽象化与实现化解耦&#xff0c;使得二者可以独立变化。这种类型的设计模式属于结构型模式&#xff0c;它通过提供抽象化和实现化之间的桥接结构&#xff0c;来实现二者的解耦。 这种模式涉及到一个作为桥接的接口&#xff0c;使得…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...