初遇事务

在MySQL5.5之前, 默认的存储引擎是MyISAM, 在5.5版本之后默认存储引擎是InnoDB, 而这两个存储引擎的最大区别就在于InnoDB是支持事务的, 这也是InnoDB取代MyISAM的重要原因. 什么是事务呢? 事务的英文是transaction, 也就是进行一次处理的基本单元, 要么完全执行, 要么全都不执行.

事务的特性: ACID

深入理解事务, 就需要知道事务的四个特性, 那就是ACID:

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
  1. A, 也就会说原子性(Aomicity). 原子的概念就是不可分割, 可以理解为组成物质的基本单元, 也就是数据处理操作的基本单位.
  2. C, 就是一致性(Consistency), 一致性指的是数据库在进行事务操作后, 会有原来的一致状态, 编程另一种一致状态. 也就是事务提交或回滚后, 数据库的完成性约束不能破坏.
  3. I, 就是隔离性(Isolocation), 指的是每个事务都是彼此独立的, 不会受到其他事务的执行影响. 简单说就是一个事务在提交之前, 对其他事务都是不可见的.
  4. D, 就是持久性(Durability), 事务提交之后对数据的修改是持久性的, 及时在系统出故障的情况下(崩溃或存储介质发生故障), 数据的修改依然是有效地. 因为当事务完成之后, 数据库的日志就会被更新, 这个通过日志, 可以让系统恢复到最后一次成功的更新状态.

这四个特性中, 原子性是基础, 隔离性是手段, 一致性是约束条件, 持久性是目的. 原子性和隔离性好理解, 至于一致性相对难, 笔者开始总是不知道这个一致性所说的状态是什么意思, 直到现在看了这个文档, 才发现.

一致性本身是由具体的业务定义的, 任何写入数据库中的数据都需要满足我们事先定义的约束规则, 到这里就可以理解一致性具体的含义了, 一致性其实说的是不违反约束规则, 比如主键约束, 唯一约束, 不为NULL约束等等.

另一个持久性, 持久性是通过事务日志来保证的. 日志包括了回滚日志和重做日志. 通过事务对数据进行修改的时候, 首先会将数据库的变化信息记录到重做日志中, 然后再对数据库中对应的行进行修改, 这样做的好处是, 即使数据库崩溃, 数据库重启后也能找到没有更新到数据库系统中的重做日志, 重新执行, 从而使事务具有持久性.

事务的控制

Oracle是支持事务的, 而在MySQL中, 需要选择合适的存储引擎才可以支持事务, 使用MySQL, 可以使用SHOW ENGINES来查看当前MySQL支持的存储引擎, 以及该引擎是否支持事务.

事务常用的控制语句:

  1. START TRANSACTION或者BEGIN, 作用是显式开启一个事务.
  2. COMMIT: 提交事务, 提交事务后, 对数据库的修改是永久性的
  3. ROLLBACK或者ROLLBACK TO [SAVEPOINT], 回滚事务, 意思是撤销正在进行的所有没有提交的修改, 或者将事务回滚到某个保存点.
  4. SAVEPOINT: 在事务中创建保存点, 方便后续针对保存点进行回滚, 一个事务中可以存在多个保存点.
  5. RELEASE SAVEPOINT: 删除某个保存点
  6. SET TRANSACTION, 设置事务的隔离级别.

使用事务有两种方式, 一种是隐式事务, 一种是显示事务. 隐式事务其实就是自动提交. Oracle默认不自动提交, 需要手写COMMIT命令, 而MySQL默认自动提交, 可以使用MySQL的命令来配置参数关闭自动提交:set autocommit = 0;是关闭自动提交, set autocommit = 1;是开启自动提交.

MySQL的默认状态下:

CREATE TABLE test(name varchar(255), PRIMARY KEY (name)) ENGINE=InnoDB;
BEGIN;
INSERT INTO test SELECT '关羽';
COMMIT;
BEGIN;
INSERT INTO test SELECT '张飞';
INSERT INTO test SELECT '张飞';
ROLLBACK;
SELECT * FROM test;

现在执行完的情况下, 数据库中默认保存了一条.

CREATE TABLE test(name varchar(255), PRIMARY KEY (name)) ENGINE=InnoDB;
BEGIN;
INSERT INTO test SELECT '关羽';
COMMIT;
INSERT INTO test SELECT '张飞';
INSERT INTO test SELECT '张飞';
ROLLBACK;
SELECT * FROM test;

现在数据库中应该是两条记录, 因为默认会隐式提交, 也就是在执行第一个INSERT INTO test SELECT '张飞';的时候, 执行完成就会提交, 只有在执行第二个的时候会产生主键冲突而回滚.

CREATE TABLE test(name varchar(255), PRIMARY KEY (name)) ENGINE=InnoDB;
SET @@completion_type = 1;
BEGIN;
INSERT INTO test SELECT '关羽';
COMMIT;
INSERT INTO test SELECT '张飞';
INSERT INTO test SELECT '张飞';
ROLLBACK;
SELECT * FROM test;

结果是一条数据, 很明显, 原因是SET @@completion_type = 1;, 这个参数有3种可能:

  1. completion=0, 这是默认情况, 也就是执行COMMIT会提交事务, 执行下一个事务前, 需要使用START TRANSACTION或者BEGIN来开启.
  2. completion=1, 这种情况下, 提交事务后, 相当于执行了COMMIT AND CHAIN, 也就是开启一个链式事务, 即当我们提交事务之后会开启一个相同隔离级别的事务.
  3. completion=2, 这种情况下COMMIT=COMMIT AND RELEASE, 也就是当提交之后, 会自动与服务器断开连接.

这里使用了completion=1, 就是提交之后, 相当于在下一行写了START TRANSACTION 或 BEGIN, 这是插入两次张飞会被认为是在同一个事务之内的操作, 所以回滚之后, 数据库中就只有一条关羽的数据.
 数据库的事务 - 初遇事务一(极客时间) Mysql

这个是事务的基本认识, 当然事务的隔离级别也很重要, 下一个随笔说.

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄