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

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

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

循环中提交事务


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

CREATE PROCEDURE load1 (count INT UNSIGNED)BEGINDECLARE s INT UNSIGNED DEFAULT 1;DECLARE c CHAR(80) DEFAULT REPEAT('a', 80);WHILE s <= count DOINSERT INTO t1 SELECT NULL,c;COMMIT;SET s=s+1;END WHILE;END;

  

CREATE PROCEDURE load2(count INT UNSIGNED)BEGINDECLARE s INT UNSIGNED DEFAULT 1;DECLARE c CHAR(80) DEFAULT REPEAT('a', 80)START TRANSACTION;WHILE s <= count DOINSERT 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()BEGINDECLARE 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()BEGINDECLARE 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 accountSET account_total = account_total + (1 + interest_rate)

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

小结


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

(0)

相关推荐

  • PHP中使用PDO操作事务的一些小测试

    PHP中使用PDO操作事务的一些小测试 关于事务的问题,我们就不多解释了,以后在学习 MySQL 的相关内容时再深入的了解.今天我们主要是对 PDO 中操作事务的一些小测试,或许能发现一些比较好玩的内 ...

  • 聊一聊mysql的锁和事务隔离级别

    锁类型 - 性能锁 从性能上来看,可以分为两种类型的锁,分别是:乐观锁和悲观锁. 乐观锁是数据版本号(version)机制实现的,一般通过为数据库表增加一个数字类型的 "version&qu ...

  • 理解purge操作

    要明白什么清空(purge)操作,你得明白什么是事务的多版本控制,即MVCC(multi-version concurrency control).Innodb为了实现MVCC, 需要在表空间内保存老 ...

  • 三大常用数据库事务详解之三:事务运行模式

    三.事务的运行模式 通常,事务以3种模式运行,他们分别是: 1. 自动提交事务 每一条单独的SQL语句都在其执行完成后进行自动提交事务,即执行 SQL 语句后就会马上自动隐式执行 COMMIT 操作. ...

  • mysql中的事务隔离级别及可重复读读提交详细分析(mvcc多版本控制/undo log)

    一.事物隔离级别 读未提交(read uncommitted)是指,一个事务还没提交时,它做的变更就能被别的事务看到.通俗理解,别人改数据的事务尚未提交,我在我的事务中也能读到. 读提交(read c ...

  • 分布式事务:两阶段提交与三阶段提交

    在分布式系统中著有 CAP 理论,该理论由加州大学伯克利分校的 Eric Brewer 教授提出,阐述了在一个分布式系统中不可能同时满足 一致性(Consistency).可用性(Availabili ...

  • 数据库事务的默认自动提交和手动提交 | 我去学习

    2019年11月4日 panda 事务提交的两种方式: 自动:当使用了增删改的语句情况下,会自动提交一次事务 手动:需要先开启,然后在提交 修改事务的默认提交方式: set @@autocommit ...

  • Mysql之锁、事务绝版详解

    一 锁的分类及特性 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则.对于任何一种数据库来说都需要有相应的锁定机制,所以MySQL自然也不能 ...

  • MySQL(一):MySQL数据库事务与锁

    基本概念 事务是指满足ACID特性的的一组操作,可以通过Commit提交事务,也可以也可以通过Rollback进行回滚.会存在中间态和一致性状态(也是真正在数据库表中存在的状态) ACID Atomi ...

  • 跟面试官侃半小时MySQL事务隔离性,从基本概念深入到实现

    来源 | 阿丸笔记 提到MySQL的事务,我相信对MySQL有了解的同学都能聊上几句,无论是面试求职,还是日常开发,MySQL的事务都跟我们息息相关. 而事务的ACID(即原子性Atomicity.一 ...

  • mysql事务隔离级别和spring Transaction事务传播

    事务的ACID原则是什么? 原子性(atomicity):最小且不可分割的.要么都执行,要么都不执行. 一致性(consistency):事务的执行使得数据库从一种正确状态转换成另一种正确状态 隔离型 ...