【MySQL技术内幕】7.8-不好的事物习惯和长事务

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 【MySQL技术内幕】7.8-不好的事物习惯和长事务

1.不好的事务习惯

1.1在循环中提交

开发人员非常喜欢在循环中进行事务的提交,下面是他们可能常写的一个存储过程:

CREATE PROCEDURE load1(count INT UNSIGNED)
BEGIN
DECLARE s INT UNSIGNED DEFAULT 1;
DECLARE c CHAR(80) DEFAULT REPEAT('a',80);
WHILE s < count DO
INSERT INTO t1 SELECT NULL,C;
COMMIT;
SET s =s+1;
END WHILE;
END;复制代码

其实,在上述的例子中,是否加上提交命令 COMMIT并不关键。因为 InnoDB存储引擎默认为自动提交,所以在上述的存储过程中去掉 COMMIT,结果其实是完全一样的。这也是另一个容易被开发人员忽视的问题:

CREATE PROCEDURE load2(count INT UNSIGNED)
BEGIN
DECLARE s INT UNSIGNED DEFAULT 1;
DECLARE c CHAR(80) DEFAULT REPEAT('a',80);
WHILE s < count DO
INSERT INTO t1 SELECT NULL,C;
SET s =s+1;
END WHILE;
END;复制代码

不论上面哪个存储过程都存在一个问题,当发生错误时,数据库会停留在一个未知的位置。例如,用户需要插入10000条记录,但是在插入5000条时,发生了错误,这时前5000条记录已经存放在数据库中,那应该怎么处理呢?另一个问题是性能问题,上面两个存储过程都不会比下面的存储过程load3快,因为下面的存储过程将所有的INSERT都放在一个事务中:

CREATE PROCEDURE load3(count INT UNSIGNED)
BEGIN
DECLARE s INT UNSIGNED DEFAULT 1;
DECLARE c CHAR(80) DEFAULT REPEAT('a',80);
START TRANSACTION;
WHILE s < count DO
INSERT INTO t1 SELECT NULL,C;
SET s =s+1;
END WHILE;
COMMIT;
END;复制代码

比较这3个存储过程的执行时间:

显然,第三种方法要快得多!这是因为每一次提交都要写一次重做日志,存储过程load1和load2实际写了10000次重做日志文件,而对于存储过程load3来说,实际只写了1次。

大多数程序员会使用第一种或第二种方法,有人可能不知道 InnoDB存储引擎自动提交的情况,另外有些人可能持有以下两种观点:首先,在他们曾经使用过的数据库中,对事务的要求总是尽快地进行释放,不能有长时间的事务;其次,他们可能担心存在 Oracle数据库中由于没有足够undo产生的 Snapshot Too old的经典问题。 MySQL的InnoDB存储引擎没有上述两个问题,因此程序员不论从何种角度出发,都不应该在一个循环中反复进行提交操作,不论是显式的提交还是隐式的提交。

1.2使用自动提交

自动提交并不是一个好的习惯,因为这会使初级DBA容易犯错,另外还可能使一些开发人员产生错误的理解,如我们在前一小节中提到的循环提交问题。 MySQL数据库默认设置使用自动提交(autocommit),可以使用如下语句来改变当前自动提交的方式:

mysql> SET autocommit=0;
Query OK, 0 rows affected (0.00 sec)复制代码

也可以使用 START TRANSACTION,BEGN来显式地开启一个事务。在显式开启事务后,在默认设置下(即参数completion_type等于0), MySQL会自动地执行SET AUTOCOMMIT=0的命令,并在 COMMIT或 ROLLBACK结束一个事务后执行SET AUTOCOMMIT=1。

另外,对于不同语言的API,自动提交是不同的。 MySQL C API默认的提交方式是自动提交,而 MySQL Python API则会自动执行 SET AUTOCOMMIT=0,以禁用自动提交。因此在选用不同的语言来编写数据库应用程序前,应该对连接 MySQL的API做好研究。

我认为,在编写应用程序开发时,最好把事务的控制权限交给开发人员,即在程序端进行事务的开始和结束。同时,开发人员必须了解自动提交可能带来的问题。我曾经见过很多开发人员没有意识到自动提交这个特性,等到出现错误时应用就会遇到大麻烦

1.3使用自动回滚

InnoDB存储引擎支持通过定义一个 HANDLER来进行自动事务的回滚操作,如在一个存储过程中发生了错误会自动对其进行回滚操作。因此我发现很多开发人员喜欢在应用程序的存储过程中使用自动回滚操作,例如下面所示的一个存储过程:

CREATE PROCEDURE sp_auto_rollback_demo (
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
START TRANSACTION;
INSERT INTO b SELECT 1;
INSERT INTO b SELECT 2;
INSERT INTO b SELECT 1;
INSERT INTO b SELECT 3;
COMMIT;
END;复制代码

存储过程 sp_auto_rollback_demo首先定义了一个exit类型的 HANDLER捕获倒错误时进行回滚。结构如下:

因此插入第二个记录1时会发生错误,但是因为启用了自动回滚的操作,因此这个存储过程的执行结果如下:

mysql>CALL sp_auto_rollback_demo;
Query OK,0 rows affected (0.06 sec)
mysql>SELECT * FROM b;
Empty set (0.00 sec)复制代码

看起来运行没有问题,非常正常。但是,执行sp_auto_rollback_demo这个存储过程的结果到底是正确的还是错误的?对于同样的存储过程sp_auto_rollback_demo,为了得到执行正确与否的结果,开发人员可能会进行这样的处理:

CREATE PROCEDURE sp_auto_rollback_demo (
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; SELECT -1; END;
START TRANSACTION;
INSERT INTO b SELECT 1;
INSERT INTO b SELECT 2;
INSERT INTO b SELECT 1;
INSERT INTO b SELECT 3;
COMMIT;
SELECT 1;
END;复制代码

当发生错误时,先回滚然后返回-1,表示运行有错误。运行正常返回值1。因此这次运行的结果就会变成:

看起来用户可以得到运行是否准确的信息。但问题还没有最终解决,对于开发人员来说,重要的不仅是知道发生了错误,而是发生了什么样的错误。因此自动回滚存在这样的一个问题。

习惯使用自动回滚的人大多是以前使用 Microsoft SQL Server数据库的开发人员。在Microsoft SQL Server数据库中,可以使用 SET XABORT ON来自动回滚一个事务。但是 Microsoft SQL Server数据库不仅会自动回滚当前的事务,还会抛出异常,开发人员可以捕获到这个异常。因此, Microsoft SQL Server数据库和 MySQL数据库在这方面是有所不同的。

就像之前小节中所讲到的,对事务的 BEGIN、 COMMIT和 ROLLBACK操作应该交给程序端来完成,存储过程需要完成的只是一个逻辑的操作,即对逻辑进行封装。

2.长事务

长事务(Long- Lived transactions),顾名思义,就是执行时间较长的事务。比如,对于银行系统的数据库,每过一个阶段可能需要更新对应账户的利息。如果对应账号的数量非常大,例如对有1亿用户的表 account,需要执行下列语句:

UPDATE account SET account_total=account_total +(1 + interest_rate)

这时这个事务可能需要非常长的时间来完成。可能需要1个小时,也可能需要4、5个小时,这取决于数据库的硬件配置。DBA和开发人员本身能做的事情非常少。然而,由于事务ACID的特性,这个操作被封装在一个事务中完成。这就产生了一个问题,在执行过程中,当数据库或操作系统、硬件等发生问题时,重新开始事务的代价变得不可接受。

数据库需要回滚所有已经发生的变化,而这个过程可能比产生这些变化的时间还要长。因此,对于长事务的问题,有时可以通过转化为小批量(mini batch)的事务来进行处理。当事务发生错误时,只需要回滚一部分数据,然后接着上次已完成的事务继续进行。

例如,对于前面讨论的银行利息计算问题,我们可以通过分解为小批量事务来完成。



相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
存储 SQL 关系型数据库
MySQL的事务隔离级别
【10月更文挑战第17天】MySQL的事务隔离级别
99 43
|
15天前
|
监控 关系型数据库 MySQL
MySQL自增ID耗尽应对策略:技术解决方案全解析
在数据库管理中,MySQL的自增ID(AUTO_INCREMENT)属性为表中的每一行提供了一个唯一的标识符。然而,当自增ID达到其最大值时,如何处理这一情况成为了数据库管理员和开发者必须面对的问题。本文将探讨MySQL自增ID耗尽的原因、影响以及有效的应对策略。
54 3
|
1月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1646 14
|
2月前
|
存储 Oracle 关系型数据库
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
从基本特性、技术选型、字段类型、事务提交方式、SQL语句、分页方法等方面对比Oracle和MySQL的区别。
546 18
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
|
1月前
|
SQL 关系型数据库 MySQL
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
尼恩,一位40岁的资深架构师,通过其丰富的经验和深厚的技術功底,为众多读者提供了宝贵的面试指导和技术分享。在他的读者交流群中,许多小伙伴获得了来自一线互联网企业的面试机会,并成功应对了诸如事务ACID特性实现、MVCC等相关面试题。尼恩特别整理了这些常见面试题的系统化解答,形成了《MVCC 学习圣经:一次穿透MYSQL MVCC》PDF文档,旨在帮助大家在面试中展示出扎实的技术功底,提高面试成功率。此外,他还编写了《尼恩Java面试宝典》等资料,涵盖了大量面试题和答案,帮助读者全面提升技术面试的表现。这些资料不仅内容详实,而且持续更新,是求职者备战技术面试的宝贵资源。
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
|
1月前
|
XML 关系型数据库 MySQL
MySQL 导出某些数据的技术详解
MySQL 导出某些数据的技术详解
132 2
|
2月前
|
SQL 关系型数据库 MySQL
MySQL基础:事务
本文详细介绍了数据库事务的概念及操作,包括事务的定义、开启、提交与回滚。事务作为一组不可分割的操作集合,确保了数据的一致性和完整性。文章还探讨了事务的四大特性(原子性、一致性、隔离性、持久性),并分析了并发事务可能引发的问题及其解决方案,如脏读、不可重复读和幻读。最后,详细讲解了不同事务隔离级别的特点和应用场景。
149 4
MySQL基础:事务
|
2月前
|
存储 关系型数据库 MySQL
技术解析:MySQL中取最新一条重复数据的方法
以上提供的两种方法都可以有效地从MySQL数据库中提取每个类别最新的重复数据。选择哪种方法取决于具体的使用场景和MySQL版本。子查询加分组的方法兼容性更好,适用于所有版本的MySQL;而窗口函数方法代码更简洁,执行效率可能更高,但需要MySQL 8.0及以上版本。在实际应用中,应根据数据量大小、查询性能需求以及MySQL版本等因素综合考虑,选择最合适的实现方案。
387 6
|
1月前
|
SQL 关系型数据库 MySQL
【MySQL】索引和事务
【MySQL】索引和事务
55 0
|
1月前
|
关系型数据库 MySQL 数据库
MySQL技术深度解析:每次最大插入条数探秘
MySQL技术深度解析:每次最大插入条数探秘
50 0

热门文章

最新文章

下一篇
无影云桌面