简单介绍MySQL中的事务机制

从一个问题开始

最近银行这个事情闹的比较厉害啊,很多储户的钱放在银行,就不翼而飞了,而银行还不管不问,说是用户的责任,打官司,用户还能输了,这就是“社会主义”。咱还是少发牢骚,多种树,莫谈国事。

说到银行存钱,就不得不说一下从银行取钱这件事情,从ATM机取钱这件简单的事情,实际上主要分为以下几个步骤:

  1. 登陆ATM机,输入密码;
  2. 连接数据库,验证密码;
  3. 验证成功,获得用户信息,比如存款余额等;
  4. 用户输入需要取款的金额,按下确认键;
  5. 从后台数据库中减掉用户账户上的对应金额;
  6. ATM吐出钱;
  7. 用户把钱拿走。

一个简单的取钱,主要分为以上几步。不知道大家有没有“天真”的想过,如果在第5步中,后台数据库中已经把钱减掉了,但是ATM还就是没有吐出钱(虽然实际也发生过,但是毕竟是低概率事件),这该怎么办?

关于这个问题,银行系统的开发人员早就想过了,那么他们是怎么来搞定这个问题的呢?这就要说到今天总结的事务这个概念了。
简单说说事务

对于上面的取钱这个事情,如果有一步出现了错误,那么就取消整个取钱的动作;简单来说,就是取钱这7步,要么都完成,要么就啥也不做。在数据库中,事务也是这个道理。

事务由一条或者多条sql语句组成,在事务中的操作,这些sql语句要么都执行,要么都不执行,这就是事务的目的。

对于事务而言,它需要满足ACID特性,下面就简要的说说事务的ACID特性。

A,表示原子性;原子性指整个数据库事务是不可分割的工作单位。只有使事务中所有的数据库操作都执行成功,整个事务的执行才算成功。事务中任何一个sql语句执行失败,那么已经执行成功的sql语句也必须撤销,数据库状态应该退回到执行事务前的状态;
    C,表示一致性;也就是说一致性指事务将数据库从一种状态转变为另一种一致的状态,在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏;
    I,表示隔离性;隔离性也叫做并发控制、可串行化或者锁。事务的隔离性要求每个读写事务的对象与其它事务的操作对象能相互分离,即该事务提交前对其它事务都不可见,这通常使用锁来实现;
    D,持久性,表示事务一旦提交了,其结果就是永久性的,也就是数据就已经写入到数据库了,如果发生了宕机等事故,数据库也能将数据恢复。

总结了一些事务的基本概念,在MySQL中,事务还是分为很多中的,下面就来看看到底有哪些事务。
有哪些事务

你能想象到吗?就这么个破事务还会分以下这么多种:

  1. 扁平事务;
  2. 带有保存点的扁平事务;
  3. 链事务;
  4. 嵌套事务;
  5. 分布式事务。

现在就来对这些事务从概念的层面上进行简单的总结一下。

    扁平事务
    扁平事务是最简单的一种,也是实际开发中使用的最多的一种事务。在这种事务中,所有操作都处于同一层次,最常见的方式如下:

   BEGIN WORK
     Operation 1
     Operation 2
     Operation 3
     ...
     Operation N
   COMMIT WORK

或者是这种:

   BEGIN WORK
     Operation 1
     Operation 2
     Operation 3
     ...
     Operation N
     (Error Occured)
   ROLLBACK WORK

扁平事务的主要缺点是不能提交或回滚事务的某一部分,或者分几个独立的步骤去提交。比如有这样的一个例子,我从呼和浩特去深圳,为了便宜,我可能这么干:

   BEGIN WORK
     Operation1:呼和浩特---火车--->北京
     Operation2:北京---飞机--->深圳
   ROLLBACK WORK

但是,如果Operation1,从呼和浩特到北京的火车晚点了,错过了航班,怎么办?感觉扁平事务的特性,那我就需要回滚,我再回到呼和浩特,那么这样成本是不是也太高了啊,所以就有了下面的第二种事务——带有保存点的扁平事务。
    带有保存点的扁平事务
    这种事务除了支持扁平事务支持的操作外,允许在事务执行过程中回滚到同一事务中较早的一个状态,这是因为可能某些事务在执行过程中出现的错误并不会对所有的操作都无效,放弃整个事务不合乎要求,开销也太大。保存点用来通知系统应该记住事务当前的状态,以便以后发生错误时,事务能回到该状态。
    链事务
    链事务,就是指回滚时,只能恢复到最近一个保存点;而带有保存点的扁平事务则可以回滚到任意正确的保存点。
    嵌套事务
    看下面这个,你就能明白了,啥是嵌套事务:

   BEGIN WORK
     SubTransaction1:
         BEGIN WORK
           SubOperationX
         COMMIT WORK
     SubTransaction2:
         BEGIN WORK
           SubOperationY
         COMMIT WORK
     ...
     SubTransactionN:
         BEGIN WORK
           SubOperationN
         COMMIT WORK
   COMMIT WORK

这就是嵌套事务,在事务中再嵌套事务,位于根节点的事务称为顶层事务。事务的前驱称为父事务,其它事务称为子事务。事务的前驱称为父事务,事务的下一层称为子事务。

子事务既可以提交也可以回滚,但是它的提交操作并不马上生效,除非由其父事务提交。因此就可以确定,任何子事务都在顶层事务提交后才真正的被提交了。同理,任意一个事务的回滚都会引起它的所有子事务一同回滚。
    分布式事务
    分布式事务通常是指在一个分布式环境下运行的扁平事务,因此需要根据数据所在位置访问网络中的不同节点,比如:通过建设银行向招商银行转账,建设银行和招商银行肯定用的不是同一个数据库,同时二者的数据库也不在一个网络节点上,那么当用户跨行转账,就是通过分布式事务来保证数据的ACID的。

MySQL中使用事务

理论总结的再好,终归都要通过实践来进行理解。下面就来说说MySQL中是如何使用事务的。

在MySQL命令行的默认设置下,事务都是自动提交的,即执行SQL语句后就会马上执行COMMIT操作。因此要显示地开启一个事务须使用命令BEGIN或START TRANSACTION,或者执行命令SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。

来看看我们可以使用哪些事务控制语句。

  1. BEGIN或START TRANSACTION;显示地开启一个事务;
  2. COMMIT;也可以使用COMMIT WORK,不过二者是等价的。COMMIT会提交事务,并使已对数据库进行的所有修改称为永久性的;
  3. ROLLBACK;有可以使用ROLLBACK WORK,不过二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
  4. SAVEPOINT identifier;SAVEPOINT允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT;
  5. RELEASE SAVEPOINT identifier;删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
  6. ROLLBACK TO identifier;把事务回滚到标记点;
  7. SET TRANSACTION;用来设置事务的隔离级别。InnoDB存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。

这些不用你“管”

有的时候有些SQL语句会产生一个隐式的提交操作,即执行完成这些语句后,会有一个隐式的COMMIT操作。有以下SQL语句,不用你去“管”:

  • DDL语句,ALTER DATABASE、ALTER EVENT、ALTER PROCEDURE、ALTER TABLE、ALTER VIEW、CREATE TABLE、DROP TABLE、RENAME TABLE、TRUNCATE TABLE等;
  • 修改MYSQL架构的语句,CREATE USER、DROP USER、GRANT、RENAME USER、REVOKE、SET PASSWORD;
  • 管理语句,ANALYZE TABLE、CACHE INDEX、CHECK TABLE、LOAD INDEX INTO CACHE、OPTIMIZE TABLE、REPAIR TABLE等。

以上的这些SQL操作都是隐式的提交操作,不需要手动显式提交。
事务的隔离级别

上面也说到了SET TRANSACTION用来设置事务的隔离级别。那事务的隔离级别是什么东东?

在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。

InnoDB存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。这些隔离级别之间的区别如下:

  • 脏读:一个事务读取到了另外一个事务没有提交的数据;
  • 比如:事务T1更新了一行记录的内容,但是并没有提交所做的修改。事务T2读取到了T1更新后的行,然后T1执行回滚操作,取消了刚才所做的修改。现在T2所读取的行就无效了;
  • 不可重复读:在同一事务中,两次读取同一数据,得到内容不同;
  • 比如:事务T1读取一行记录,紧接着事务T2修改了T1刚才读取的那一行记录。然后T1又再次读取这行记录,发现与刚才读取的结果不同。这就称为“不可重复”读,因为T1原来读取的那行记录已经发生了变化;
  • 幻读:同一事务中,用同样的操作读取两次,得到的记录数不相同;
  • 比如:事务T1读取一条指定的WHERE子句所返回的结果集。然后事务T2新插入 一行记录,这行记录恰好可以满足T1所使用的查询条件中的WHERE子句的条件。然后T1又使用相同的查询再次对表进行检索,但是此时却看到了事务T2刚才插入的新行。这个新行就称为“幻像”,因为对T1来说这一行就像突然出现的一样。

隔离级别越低,事务请求的锁越少或保持锁的时间就越短。InnoDB存储引擎默认的支持隔离级别是REPEATABLE READ;在这种默认的事务隔离级别下已经能完全保证事务的隔离性要求,即达到SQL标准的SERIALIZABLE级别隔离。

我们可以可以用SET TRANSACTION语句改变单个会话或者所有新进连接的隔离级别。它的语法如下:

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

注意:默认的行为(不带session和global)是为下一个(未开始)事务设置隔离级别。如果使用GLOBAL关键字,语句在全局对从那点开始创建的所有新连接(除了不存在的连接)设置默认事务级别。你需要SUPER权限来做这个。使用SESSION 关键字为将来在当前连接上执行的事务设置默认事务级别。 任何客户端都能自由改变会话隔离级别(甚至在事务的中间),或者为下一个事务设置隔离级别。

mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)

总结

这篇文章,基本上都是理论概念的堆积,实战的东西基本没有。但是,这些都不是问题,这也无法阻挡这篇文章成为一篇读者喜欢的文章,是吧。好了,这篇关于MySQL中事务的文章就到此结束,以后如果有新的东西,就接着总结。

(0)

相关推荐

  • NodeJs使用Mysql模块实现事务处理实例

    依赖模块: 1. mysql:https://github.com/felixge/node-mysql npm install mysql --save 2. async:https://github.com/caolan/async npm install async --save (ps: async模块可换成其它Promise模块如bluebird.q等) 因为Node.js的mysql模块本身对于事务的封装过于简单,而且直接使用会有很严重callback hell,故我们封装了两个方法

  • MySQL中Innodb的事务隔离级别和锁的关系的讲解教程

    前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力.所以对于加锁的处理,可以说就是数据库对于事务处理的精髓所在.这里通过分析MySQL中InnoDB引擎的加锁机制,来抛砖引玉,让读者更好的理解,在事务处理中数据库到底做了什么. 一次封锁or两段锁? 因为有大量的并发访问,为了预防死锁,一般应用中推荐使用一次封锁法,就是在方法的开始阶段,已经预先知道会

  • PHP入门教程之使用Mysqli操作数据库的方法(连接,查询,事务回滚等)

    本文实例讲述了PHP入门教程之使用Mysqli操作数据库的方法.分享给大家供大家参考,具体如下: Demo1.php <?php //使用 mysqli 对象操作数据库 //创建 mysqli 对象(资源句柄) $_mysqli = new mysqli(); //连接数据库 1.主机名(ip) 2.账户 3.密码 4.数据库 //mysqli_connect 函数 == $_mysqli -> connect(); $_mysqli -> connect('localhost','ro

  • 深入理解MySQL中的事务机制

    使用数据库事务可以确保除事务性单元内的所有操作都成功完成.MySQL中的InnoDB引擎的表才支持transaction.在一个事务里,如果出现一个数据库操作失败了,事务内的所有操作将被回滚,数据库将会回到事务前的初始状态.有一些不能被回滚的语句:将在本文的最后讨论. 在一个web应用中,会很经常遇到需要使用事务的地方,要么希望若干语句都执行成功,要么都不执行,如果出现有些执行成功,而其他的失败将会导致数据损坏. 在这篇文章的例子中,我们使用下面的两张表"employee"和"

  • Mysql事务操作失败如何解决

    Mysql事务操作失败如何解决 事务的原子性 :事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做 . 要实现事务的原子性,单单靠一条commit或是rollback命令还是不行的,因为例如commit命令它只是将一个事务中执行成功的DML语句提交给数据库里.如果要实现事务的原子性,则就需要commit和rollback命令配合上程序上的一个业务逻辑才能可以,具体业务逻辑代码如下示例代码: 1.现象 程序中打开了事务进行插入,但是没有commit,表中的数据已经存在,就是回滚也不

  • MySQL 四种事务隔离级别详解及对比

    MySQL 四种事务隔离级别详解及对比 按照SQL:1992 事务隔离级别,InnoDB默认是可重复读的(REPEATABLE READ).MySQL/InnoDB 提供SQL标准所描述的所有四个事务隔离级别.你可以在命令行用--transaction-isolation选项,或在选项文件里,为所有连接设置默认隔离级别. 例如,你可以在my.inf文件的[mysqld]节里类似如下设置该选项: transaction-isolation = {READ-UNCOMMITTED | READ-CO

  • 深入解析MySQL的事务隔离及其对性能产生的影响

    SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的.低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销. Read Uncommitted(读取未提交内容)        在该隔离级别,所有事务都可以看到其他未提交事务的执行结果.本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少.读取未提交的数据,也被称之为脏读(Dirty Read). Read Committed(读取提交内容)        这是大多数数据库系统的默认隔离

  • 简单介绍MySQL中的事务机制

    从一个问题开始 最近银行这个事情闹的比较厉害啊,很多储户的钱放在银行,就不翼而飞了,而银行还不管不问,说是用户的责任,打官司,用户还能输了,这就是"社会主义".咱还是少发牢骚,多种树,莫谈国事. 说到银行存钱,就不得不说一下从银行取钱这件事情,从ATM机取钱这件简单的事情,实际上主要分为以下几个步骤: 登陆ATM机,输入密码: 连接数据库,验证密码: 验证成功,获得用户信息,比如存款余额等: 用户输入需要取款的金额,按下确认键: 从后台数据库中减掉用户账户上的对应金额: ATM吐出钱:

  • 简单介绍MySQL中索引的使用方法

    数据库索引是一个数据结构,提高操作的速度,在一个表中可以使用一个或多个列,提供两个快速随机查找和高效的顺序访问记录的基础创建索引. 在创建索引时,它应该被认为是将SQL查询的那些列上创建一个或多个索引的列. 实际上,指数也保持主键或索引字段和指针的实际表中每条记录的表型. 用户无法看到索引,它们只是用来加快查询速度,将用于数据库搜索引擎找到的记录速度非常快. INSERT和UPDATE语句表上的索引需要更多的时间,成为快速对这些表的SELECT语句.究其原因是,当进行插入或更新,数据库以及需要惰

  • 简单介绍MySQL中GROUP BY子句的使用

    可以使用GROUP BY组值一列,并且如果愿意的话,可以将该列进行计算.使用COUNT,SUM,AVG等功能的分组列. 要了解GROUP BY子句考虑的EMPLOYEE_TBL的的表具有以下记录: mysql> SELECT * FROM employee_tbl; +------+------+------------+--------------------+ | id | name | work_date | daily_typing_pages | +------+------+----

  • 全面了解MySql中的事务

    最近一直在做订单类的项目,使用了事务.我们的数据库选用的是MySql,存储引擎选用innoDB,innoDB对事务有着良好的支持.这篇文章我们一起来扒一扒事务相关的知识. 为什么要有事务? 事务广泛的运用于订单系统.银行系统等多种场景.如果有以下一个场景:A用户和B用户是银行的储户.现在A要给B转账500元.那么需要做以下几件事: 1. 检查A的账户余额>500元: 2. A账户扣除500元: 3. B账户增加500元: 正常的流程走下来,A账户扣了500,B账户加了500,皆大欢喜.那如果A账

  • 简单了解 MySQL 中相关的锁

    本文主要是带大家快速了解 InnoDB 中锁相关的知识 基础概念解析和RocketMQ详细的源码解析 http://xiazai.jb51.net/202105/yuanma/RocketMQ_jb51.rar 为什么需要加锁 首先,为什么要加锁?我想我不用多说了,想象接下来的场景你就能 GET 了. 你在商场的卫生间上厕所,此时你一定会做的操作是啥?锁门.如果不锁门,上厕所上着上着,啪一下门就被打开了,可能大概也许似乎貌似有那么一丁点的不太合适. 数据也是一样,在并发的场景下,如果不对数据加锁

  • 讲解MySQL中的事务特性

    一个事务是一个连续的一组数据库操作,就好像它是一个单一的工作单元进行.换言之,永远不会是完整的事务,除非该组内的每个单独的操作是成功的.如果在事务的任何操作失败,则整个事务将失败. 实际上,会俱乐部许多SQL查询到一个组中,将执行所有的人都一起作为事务的一部分. 事务的特性: 事务有以下四个标准属性的缩写ACID,通常被称为: 原子性: 确保工作单元内的所有操作都成功完成,否则事务将被中止在故障点,和以前的操作将回滚到以前的状态. 一致性: 确保数据库正确地改变状态后,成功提交的事务. 隔离性:

  • 简单介绍java中equals以及==的用法

    简单介绍 equals方法是java.lang.Object类的方法有两种用法说明: 一.对于字符串变量来说,使用"=="和"equals()"方法比较字符串时,其比较方法不同. 1."=="比较两个变量本身的值,即两个对象在内存中的首地址.(java中,对象的首地址是它在内存中存放的起始地址,它后面的地址是用来存放它所包含的各个属性的地址,所以内存中会用多个内存块来存放对象的各个参数,而通过这个首地址就可以找到该对象,进而可以找到该对象的各个属

  • 简单了解Spring中的事务控制

    1.事务的概念 事务是一组操作的执行单元,相对于数据库的单条操作而言,事务管理的是一组SQL指令,如增删改查等,事务的特性体现在事务内包含的SQL指令必须全部执行成功,如果其中一条指令发生错误,那么整个事务内的一组操作都要进行回滚. 事务有四个特性: 原子性 Atomic ,事务是一个不可再拆分的最小单位,要么整个执行,要么整个回滚. 一致性 Consistent,事务要保证数据库整体数据的完整性和业务的数据的一致性,事务成功提交整体数据修改,事务错误则回滚到数据回到原来的状态. 隔离性 Iso

  • 一文介绍mysql中TINYINT取值范围

    目录 项目场景: 问题描述: 原因分析: 解决方案: 项目场景: 最近在开发过程中,看见表设计中是thinyint字段,但对于它的范围产生了好奇 问题描述: 当我们填写超过128数值的时候,该字段就会报以下错误 Cause:com.mysql.jdbc.MysqlDataTruncation:Data truncation:Out of range value for column 'priority' at row 1; 原因分析: 从 -2^7 (-128) 到 2^7 - 1 (127)

随机推荐