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. bayaim——docker.txt

    #菜鸟教程地址https://www.runoob.com/docker/docker-tutorial.html#docker官方地址仓库https://hub.docker.com/ ------ ...

  2. 28.web8

    file_get_contents()文件包含漏洞,根据题目提示txt?尝试flag.txt payload:  ?ac=flags&fn=flag.txt

  3. 微软与阿里云合作推出“开放应用模型(OAM)”

    英文原文:Announcing the Open Application Model (OAM) 原文标题:微软与阿里云合作推出“开放应用模型(OAM)” 用于 Kubernetes 及更多平台的应用 ...

  4. css3 中的渐变

    虽说css3 都已经使用多年了,但是关于css3的渐变用的很少.今天遇见了,就学习了一下. 首先我们打开ps,新建一个画布,选择渐变工具,这个时候我们能够看到顶栏上面的渐变类型如下 第一个我们选中的是 ...

  5. YII2中andWhere多个or查询

    使用多个or的复杂查询: AND ((`name`='张三') OR (`name`='李四') OR (`name`='王五')) // AND ((`name`='张三') OR (`name`= ...

  6. Java集合内容

    Java的集合类定义在java.util包中,支持泛型,主要提供了3种集合类,包括List,Set和Map.Java集合使用统一的Iterator遍历. 1.List遍历 实现了Iterator接口的 ...

  7. 8 种经常被忽视的 SQL 错误用法,你有没有踩过坑?

    1.LIMIT 语句 分页查询是最常用的场景之一,但也通常也是最容易出问题的地方.比如对于下面简单的语句,一般 DBA 想到的办法是在 type, name, create_time 字段上加组合索引 ...

  8. 有了AOE,妈妈再也不用担心我的模型管理!

    前言 越来越多的业务会用到AI相关的技术,大多数的AI模型是部署在云端使用的,毕竟服务端计算更快,管理也更容易.随着终端设备性能提升,在终端使用 AI 模型有了更大的价值,可以更好满足业务对响应实时性 ...

  9. Ribbon负载均衡及Feign消费者调用服务

    微服务调用Ribbon 简介 前面讲了eureka服务注册与发现,但是结合eureka集群的服务调用没讲. 这里的话 就要用到Ribbon,结合eureka,来实现服务的调用: Ribbon是Netf ...

  10. nmcli详解

    1. nmcli 安装 [root@liujunjun ~]# yum install -y NetworkManager CentOS7默认已安装了 2. nmcli 基本选项 选项 作用 -t 简 ...