MySQL 事务提交 --不良好的事务习惯

  我们知道"事务"是数据库区别于文件系统的重要特性之一。MySQL的InnoDB引擎中的事务也完全符合ACID(原子性 一致性 隔离性 持久性)的特性。事务以及事务提交等一些内容不可避免的会出现在我们的日常工作当中。这篇文章我们就来简单的聊聊一些不良好的事务习惯。

循环中提交事务


  我们先来比较两个存储过程

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;

  

CREATE PROCEDURE load2(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;

  因为InnoDB存储引擎默认是自动提交的,所以load1中如果去掉Commit语句,结果也是一样的。单纯比较两个存储过程我们就可以知道,load1中存在一个问题,例如当用户需要插入10000条记录,但是在插入第5000条时,发生了错误,这时前5000条记录已经存放在数据库中。而load2中整体都是放在一个事务中,所以不会出现这个问题。除此之外,这两个存储过程的性能也存在差别,load2要比load1快出许多,这是因为每一次提交都要写一次redo log,存储过程load1实际上写了10000次重做日志,而对于存储过程load2来说,实际只写了1次redo log。因此执行时间会有巨大的差距。

  在别的一些数据库中,可能总是要求对事务尽快地释放,不能有长时间的事务;其次,可能担心存在Oracle数据库中由于没有足够undo产生的Snapshot Too Old的经典问题。MySQL的InnoDB引擎没有上述的问题,因此无论是何种角度,都不应该在一个循环中反复进行提交操作,不论是显式的还是隐式的提交。

使用自动提交


  自动提交不是一个好的习惯,因为这可能使开发人员产生错误的理解。我们可以使用如下语句来改变当前自动提交的方式:

SET autocommit=0;

  也可以使用START TRANSACTION, BEGIN来显式地开启一个事务。在显式开启事务后,在默认设置下(即参数completion_type等于0),MySQL会自动地执行SET AUTOCOMMIT=0的命令,并在COMMIT或ROLLBACK结束一个事务后执行SET AUTOCOMMIT=1。此外对于不同语言的API,自动提交是不同的,因此在选用不同的语言来编写数据库应用程序前,应该对连接MySQL的API做好研究。

使用自动回滚


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

CREATE TABLE 'b' (
'a' int(11) NOT NULL DEFAULT '0',
PRIMARY KEY ('a')
) ENGINE=InnoDB DEFAULT CHARSET=latin1

  

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时会发生错误,但是因为启用了自动回滚操作,因此这个存储过程的执行结果是没有问题的,看起来非常正常。但我们并不能看出这个存储过程的结果到底是正确还是错误的。为了得到执行正确与否的结果,开发人员可能会进行这样的处理:

CREATE PROCEDURE sp_auto_rollback_demo()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION 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。但是其实问题还是没有解决,对开发人员来说,重要的不仅是知道是否发生了错误,还要知道发生了什么错误。因此自动回滚存在这样一个问题。这里其实有一个建议是:对事务的BEGIN,COMMIT和ROLLBACK操作应该交给程序端来完成,存储过程需要完成的只是一个逻辑操作,即对逻辑进行封装。在程序中控制事务的好处是,用户可以得知发生错误的原因。

长事务


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

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

  这个事务可能需要非常长的时间来完成。由于事务ACID的特性,这个操作被封装在一个事务中完成,这就产生了一个问题,在执行过程中,当数据库或操作系统,硬件等发生问题时,重新开始事务的代价变得不可接受。数据库需要回滚所有已经发生的变化,而这个过程可能比产生这些变化的时间还要长。因此,对于长事务的问题,有时候可以通过转化为小批量的事务来进行处理。当事务发生错误时,只需要回滚一部分数据,然后接着上次已经完成的事务继续进行。

小结


  事务是数据库区别于文件系统的一个关键特性。事务必须遵循ACID特性,即Atomicity(原子性), Consistency(一致性), Isolation(隔离性) 和 Durability(持久性)。隔离性通过锁来完成,原子性,一致性,隔离性通过redo和undo来完成。在默认配置下,MySQL InnoDB总是自动提交的,如果不知道这点,可能会带来不好的结果。此外,在应用程序中,最好的做法是把事务的START TRANSACTION, COMMIT, ROLLBACK操作交给程序段来完成,而不是在存储过程中完成。

MySQL 事务提交 --不良好的事务习惯。的更多相关文章

  1. MySQL存储引擎,优化,事务

    1唯一约束unique和主键key的区别?     1.什么是数据的存储引擎?       存储引擎就是如何存储数据.如何为存储的数据建立索引和如何更新.查询数据等技术的实现方法.因为在关系数据库中数 ...

  2. 分布式事务_03_2PC框架raincat源码解析-事务提交过程

    一.前言 前面两节,我们已经将raincat的demo工程启动,并简单分析了下事务协调者与事务参与者的启动过程. 这一节,我们来看下raincat的事务提交过程. 二.事务提交过程概览 1.二阶段对应 ...

  3. 【Spring】Spring的事务管理 - 1、Spring事务管理概述(数据库事务、Spring事务管理的核心接口)

    Spring事务管理概述 文章目录 Spring事务管理概述 数据库事务 什么是Spring的事务管理? Spring对事务管理的支持 Spring事务管理的核心接口 Platform Transac ...

  4. mysql源码解读之事务提交过程(二)

    上一篇文章我介绍了在关闭binlog的情况下,事务提交的大概流程.之所以关闭binlog,是因为开启binlog后事务提交流程会变成两阶段提交,这里的两阶段提交并不涉及分布式事务,当然mysql把它称 ...

  5. mysql源码解读之事务提交过程(一)

    mysql是一种关系型数据库,关系型数据库一个重要的特性就是支持事务,这是区别于no-sql产品的一个核心特性.当然了,no-sql产品支持键值查询,不能支持sql语句,这也是一个区别.今天主要讨论下 ...

  6. MySQL binlog 组提交与 XA(分布式事务、两阶段提交)【转】

    概念: XA(分布式事务)规范主要定义了(全局)事务管理器(TM: Transaction Manager)和(局部)资源管理器(RM: Resource Manager)之间的接口.XA为了实现分布 ...

  7. mysql 事务提交过程

     打开binlog选项后,执行事务提交命令时,就会进入两阶段提交模式.两阶段提交分为prepare阶段和commit两个阶段.流程如下 :这里面涉及到两个重要的参数:innodb_flush_log_ ...

  8. PHP 中mysql如何实现事务提交?

    事务就是指对数据库的多次修改,要么全部成功,要么全部失败,不能出现部分修改成功,部分修改失败的情况. PHP下操作mysql数据库要实现事务提交,需注意以下方面: 1, 数据库表存储引擎类型设置为in ...

  9. 左右mysql事务提交

    package com.itheima.trans; import java.sql.Connection; import java.sql.PreparedStatement; import jav ...

随机推荐

  1. .NET Core 发布(dotnet publish)

    目录 一.需求 二.方法 三.参考 一.需求 使用.net core 3.0建的项目,一般情况下,每次想发布都要打开vs,然后点击发布,选择配置: 如果想用cmd命令行发布,应该怎么写呢? 二.方法 ...

  2. 活久见: maven pom 竟然都会崩溃!

    问题是: 我的应用的pom 并没有任何报错,但是代码报错,而且编译不通过. 如下,我本地项目,从 spring-cloud-alibaba-dependencies 0.2.1.RELEASE 升级到 ...

  3. IT兄弟连 HTML5教程 CSS3属性特效 圆角

    传统的圆角生成方案,必须使用多张图片作为背景图案.CSS3的出现,使得我们再也不必浪费时间去制作这些图片了,只需要border-radius属性,支持浏览器IE 9.Opera 10.5.Safari ...

  4. 数据结构学习--单循环链表(python)

    概念 将单链表的终端节点的指针由原来的空指针改为指向头节点, 就是整个单链表形成一个环, 这种首尾相接的单链表称为单循环链表. 实现 class Node: """ 节点 ...

  5. VUE程序调试的方法

    目录 VUE程序调试的方法 1.写本文的背景 2.调试与测试 3.Console调试法 3.1 添加console.log指令 3.2 调出温度界面如下 3.3 Google浏览器的Console窗口 ...

  6. Change Style of Navigation Items 更改导航项的样式

    In this lesson, you will learn how to change the style of navigation items in a WinForms XAF applica ...

  7. Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新

    SystemUI系列文章 Android8.1 MTK平台 SystemUI源码分析之 Notification流程 Android8.1 MTK平台 SystemUI源码分析之 电池时钟刷新 And ...

  8. 速查 objc中可变集合和不可变集合的遍历性能

    次数 : 5,000,000 NSMutableArray //0.131999/0.116085/0.112128 NSArray //0.116842/0.111675/0.108623 NSMu ...

  9. python科学计算和数据分析常用库

    NumPy NumPy最强大的是n维数组,该库还包含基本的线性代数函数.傅立叶变换.随机函数和其他底层语言(如Fortran.C和C++)集成的工具. SciPy SciPy建立在NumPy基础上,它 ...

  10. WEB UI分布式自动化测试框架

    Github地址: https://github.com/zhangweixu/Autotest.git