首页 > 数据库 >MySQL 死锁后事务无法回滚是真的吗?

MySQL 死锁后事务无法回滚是真的吗?

时间:2023-11-10 12:05:56浏览次数:40  
标签:回滚 rows 0.00 MySQL 死锁 sec mysql test deadlock


MySQL  死锁后事务无法回滚是真的吗?_数据库


MySQL 作为目前互联网企业使用最多的,或者说在基于成本下,最流行的数据库之一,MySQL 在国内使用者众多,那么在MySQL偶然安装后,在使用中出现死锁后,死锁中的事务到底能不能回滚 ?我们来进行相关的实验

我们先验证一遍

1 我们打开一个MySQL 版本为 8.027 官方版本

MySQL  死锁后事务无法回滚是真的吗?_mysql_02

2 通过下面的操作我们可以确认两个分屏访问的是同一个MySQL的数据库

MySQL  死锁后事务无法回滚是真的吗?_MySQL_03

3 我们在其中建立一张表,并且插入数据

MySQL  死锁后事务无法回滚是真的吗?_数据库_04

4  我们通过数据库的操作原理,产生了一个死锁条件,让下面的操作产生了死锁,并让数据通过自身的工作原理,解开了死锁。

MySQL  死锁后事务无法回滚是真的吗?_mysql_05

5  然后我们对相关的表进行数据查询,看最终我们的数据表产生了什么最终的结果

MySQL  死锁后事务无法回滚是真的吗?_数据库_06

6  我们再次验证,MySQL 数据库的隔离级别,我们并未选择MySQL的默认隔离级别 Repeatable Read ,而是我们大多数数据库包含Oracle 常用的 read committed

MySQL  死锁后事务无法回滚是真的吗?_数据库_07

好了现在我们来捋一捋结果,到底是不是如PostgreSQL 老师们Diss ,MySQL 存在死锁时,部分提交的问题,并且违反了事务的ACID的特性。

我们先把A 面的操作都用文本列出来

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.27    |
+-----------+
1 row in set (0.00 sec)

mysql> use test;
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| orders         |
| payments       |
| test_deadlock  |
+----------------+
3 rows in set (0.00 sec)

mysql> drop table test_deadlock;
Query OK, 0 rows affected (0.04 sec)

mysql> create table test_deadlock (id int primary key,name varchar(255));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test_deadlock (id,name) values (1,'a');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_deadlock (id,name) values (2,'b');
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_deadlock;
+----+------+
| id | name |
+----+------+
|  1 | a    |
|  2 | b    |
+----+------+
2 rows in set (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test_deadlock(id,name) values (3,'c');
Query OK, 1 row affected (0.01 sec)

mysql> update test_deadlock set name = 'd' where id = 1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update test_deadlock set name = 'd' where id = 1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql> update test_deadlock set name = 'd' where id = 2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> commit;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from test_deadlock;
+----+------+
| id | name |
+----+------+
|  1 | d    |
|  2 | e    |
|  3 | c    |
+----+------+
3 rows in set (0.00 sec)

mysql> show variables like '%isolation%';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+

我们在把B面的文字给大家展示

mysql> 
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.27    |
+-----------+
1 row in set (0.00 sec)

mysql> use test;
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| orders         |
| payments       |
| test_deadlock  |
+----------------+
3 rows in set (0.00 sec)

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| orders         |
| payments       |
+----------------+
2 rows in set (0.00 sec)

mysql> select * from test_deadlock;
+----+------+
| id | name |
+----+------+
|  1 | a    |
|  2 | b    |
+----+------+
2 rows in set (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> 
mysql> 
mysql> 
mysql> update test_deadlock set name = 'e' where id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update test_deadlock set name = 'd' where id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test_deadlock;
+----+------+
| id | name |
+----+------+
|  1 | d    |
|  2 | e    |
|  3 | c    |
+----+------+
3 rows in set (0.00 sec)

mysql> show variables like '%isolation%';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set (0.00 sec)

结论,的确MySQL 在发生死锁的情况下,会有事务部分提交的问题,从上面的图和文本可以看出,A 事务中,插入数据和对数据第一行的修改,均生效了,而按照数据库的事务部分的既定原理,这是不可以的,事务要么回滚,要么全部执行。

实际上,这个问题和死锁本身关系不大,我们通过这样一个情景可以再次验证问题

MySQL  死锁后事务无法回滚是真的吗?_数据库_08

我们在把文字进行展示

A 操作后的结果

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from test_deadlock where id = 1;
Query OK, 1 row affected (0.00 sec)

mysql> insert into test_deadlock (id,name) values (3,'d');
ERROR 1062 (23000): Duplicate entry '3' for key 'test_deadlock.PRIMARY'
mysql> 
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test_deadlock;
+----+------+
| id | name |
+----+------+
|  1 | d    |
|  2 | e    |
|  3 | c    |
+----+------+
3 rows in set (0.00 sec)

B 操作后的结果

1 row in set (0.00 sec)

mysql> 
mysql> 
mysql> 
mysql> 
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from test_deadlock where id = 1;
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_deadlock (id,name) values (3,'d');
ERROR 1062 (23000): Duplicate entry '3' for key 'test_deadlock.PRIMARY'
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test_deadlock;
+----+------+
| id | name |
+----+------+
|  2 | e    |
|  3 | c    |
+----+------+
2 rows in set (0.00 sec)

从上的结果看,实际上在事务出现操作错误后,按照数据库原理是应该全部回滚的,而B 操作中,我们commit 是会部分进行提交的,也就是把错误的操作不提交,而正确的操作提交。

结论最终的结果是------是的MySQL 在事务操作中,并不是按照我们认为的数据库原理进行事务的操作的,或者更准确的说,一部分不是我们认为的那样。

这里我们也有其他类似的设计,这个数据库就是 SQL SERVER ,使用过SQL SERVER 的小伙伴,不知道注意到没有SQL SERVER 本身默认安装后,也是和MySQL 一样的,事务错误后会部分提交事务中错误发生前正确的部分。

这样的设计有一种说法,MySQL本身就不是给金融类产品使用的,而是定位于WEB 类型的数据库产品,而web 类的数据库产品本身就更具有灵活性,同时需要更快的速度,将很多问题都简化和改变的情况,这里我们可以从MySQL 在处理事务的和存储过程的建议,或者说民间使用MySQL的建议,不建议大事务,不建议存储过程大量的在业务中使用的这个‘口耳相传’的论调,找寻到一些最初MySQL 被设计出来的最初的初衷。

所以数据库本身是有定位的,不是一个数据库走天下,不同的数据库定位的业务不同,定位的使用者和业务的逻辑不同。当然事务不完全回滚对于使用者本身是不是一个问题,具体我们需要看业务的设定是不是允许或接受,如同MySQL 本身也在表设计时也不希望遵循 三范式一样。MySQL 是一个反传统的数据库产品。

但是 但是 但是  MySQL 可以解决这个问题,我们有参数可以解决。这点和SQL SERVER 是一样的。

MySQL  死锁后事务无法回滚是真的吗?_mysql_09

经过我们的调整MySQL的参数后,MySQL 满足了我们传统的数据库对于事务中的要求,要么全回滚,要么全不回滚。

MySQL  死锁后事务无法回滚是真的吗?_mysql_10

A 和 B 事务代码,事务A 中的插入是没有生效的,从而证明MySQL 完全可以实现在死锁后死锁事务的全部回滚。顺便打一个广告 2023-08-22日晚8点,大家可以了解PolarDB 了解一下,我们请来PolarDB的基础架构研发负责人 来回答大家对于PolarDB数据库的问题,吃不了亏,上不了当 !(具体参见地址在文章最下方)

备注:关于SQL SERVER 部分提交的问题

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test_deadlock(id,name) values (4,'g');
Query OK, 1 row affected (0.00 sec)

mysql> update test_deadlock set name = 'd' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update test_deadlock set name = 'e' where id = 2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test_deadlock;
+----+------+
| id | name |
+----+------+
|  1 | d    |
|  2 | e    |
|  3 | c    |
+----+------+
3 rows in set (0.00 sec)


mysql> 
mysql> select * from test_deadlock;
+----+------+
| id | name |
+----+------+
|  1 | a    |
|  2 | e    |
|  3 | c    |
+----+------+
3 rows in set (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update test_deadlock set name = 'e' where id = 2;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql> update test_deadlock set name = 'd' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

标签:回滚,rows,0.00,MySQL,死锁,sec,mysql,test,deadlock
From: https://blog.51cto.com/u_14150796/8294789

相关文章

  • MySQL 内部Server 层机制
    主要包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。1.连接器像navicat、JDBC、MySQL等客户端软件需要先和mysql建立通信之后......
  • MySQL8
    MySQL8.0:窗口函数一、MySQL8.0窗口函数概述1、什么是窗口函数窗口函数是类似于可以返回聚合函数值的函数,例如SUM(),COUNT(),MAX()。但是窗口函数又与普通的聚合函数不一样,它不会对结果进行分组,使输出中的行数和输入中的行数相同。窗口函数示例:selectsum()over(partitionby_......
  • windows系统上如何给mysql导入数据库和表
    1.连接数据库2.输入密码3.进入数据库4.创建数据库 createdatabase数据库名;5.进入数据库use  数据库名;6.查看当前所在数据库selectdatabase();7.把需要导入的数据库放到没有中文名的路径下面(蜜蜂这里放D盘了),之后使用SOURCE导入SOURCE数据库的位置/需要导入的数据库名称(中间......
  • mysql基本使用
    MySQL常用图形化工具:NavicatSqlyogMysqlworkbend(msi自动安装) //////////////////////////////////////////////////////////Mysql数据库基本操作1、ddl数据定义语言对数据库的常用操作 l 查看所有的数据库:showdatabases;l 创建数据库:createdatabase[i......
  • datax抽取mysql数据到hive报错:javax.net.ssl.SSLException: Connection reset
    datax抽取mysql数据报错:[INFO]2023-11-0912:35:14.090+0000-->2023-11-0920:35:13.492[0-0-0-reader]ERRORReaderRunner-ReaderrunnerReceivedExceptions:com.alibaba.datax.common.exception.DataXException:Code:[DBUtilErrorCode-07],Description:[......
  • 远程连接 Mysql 失败的解决方法
    今天在虚拟机Ubuntu上折腾了一晚上mysql,然后试着用java连接,搞了很久都没成功,但是同学配好的Debian上却连接成功了,也就是说我的配置有问题。折腾了很久,最后还是通过理解异常信息来大致猜测。远程连接是输入mysql所在主机的IP和端口来确定主机的逻辑地址,再通过用户和密码来确定登......
  • 线上SQL超时场景分析-MySQL超时之间隙锁
    前言之前遇到过一个由MySQL间隙锁引发线上sql执行超时的场景,记录一下。背景说明分布式事务消息表:业务上使用消息表的方式,依赖本地事务,实现了一套分布式事务方案消息表名:mq_messages数据量:3000多万索引:create_time和statusstatus:有两个值,1和2,其中99%以上的状态都是2,表......
  • mysql产生临时表的原因有哪些?
    mysql产生临时表的原因有哪些?排序操作:如果查询语句中包含了ORDERBY子句,MySQL就会使用临时表来存储排序结果。分组操作:如果查询语句中包含了GROUPBY子句,MySQL就会使用临时表来存储分组结果。连接操作:如果查询语句中包含了JOIN子句,MySQL可能会使用临时表来存储连接结果。子查......
  • 常用mysql命令记录
    显示当前数据库列表:SHOWDATABASES;创建新数据库:CREATEDATABASEdatabase_name;这将创建一个名为“database_name”的新数据库。切换到指定数据库:USEdatabase_name;这会将当前会话切换到“database_name”数据库。显示当前数据库中的表:SHOWTABLES;创建表:CREATETABLEtable_......
  • Mysql问题
    按照黑马安装mysql,调用cmd,输入mysql,回车之后跟教程上显示的不一样:我显示的是:mysql8.0ERROR1045(28000):Accessdeniedforuser‘ODBC‘@‘localhost‘(usingpassword:NO) 解决方法在:终极解决mysql8.0ERROR1045(28000):Accessdeniedforuser‘ODBC‘@‘l......