1.事务介绍

  • 在 MySQL 中只有使用了 InnoDB 存储引擎的数据库或表才支持事务

  • 事务主要针对DML语句(UPDATE、INSERT、DELETE)

  • 一组数据操作执行步骤,这些步骤被视为一个工作单元

    1. 用于对多个语句进行分组
    2. 可以在多个客户机并发访问同一个表中的数据时使用
  • 在事务中,所有步骤都执行成功或都执行失败

    1. 如果所有步骤正常,则执行
    2. 如果步骤出现错误或不完整,则取消

2.事务ACID特性

  • 原子性(Atomicity,或称不可分割性)

一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

  • 一致性(Consistency)

在事务开始之前和事务结束以后,数据库的完整性没有被破坏。例如,完整性约束了a+b=10,一个事务改变了a,那么b也应该随之改变。

  • 隔离性(Isolation,又称独立性)

数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。更加具体的来讲,就是事务之间的操作是独立的。

  • 持久性(Durability)

事务执行成功以后,该事务对数据库所作的更改便是持久的保存在数据库之中,不会无缘无故的回滚

3.事务的生命周期

  • 一个成功的事务周期
BEGIN;		#事务开始
...
DML语句
...
ROLLBACK; #提交事务
  • 一个失败的事务周期
BEGIN;		#事务开始
...
DML语句
...
ROLLBACK; #回滚事务

4.事务的控制语句

START TRANSACTION(或 BEGIN):显式开始一个新事务
SAVEPOINT:分配事务过程中的一个位置,以供将来引用
COMMIT:永久记录当前事务所做的更改
ROLLBACK:取消当前事务所做的更改
ROLLBACK TO SAVEPOINT:取消在 savepoint 之后执行的更改
RELEASE SAVEPOINT:删除 savepoint 标识符
SET AUTOCOMMIT:为当前连接禁用或启用默认 autocommit 模式

注意

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

4.1 自动提交

  • 查看自动提交
mysql> SHOW VARIABLES LIKE "autocommit";
  • 临时关闭自动提交
mysql> SET autocommit=0;
  • 永久关闭自动提交(修改配置文件)
$ vim /etc/my.cnf
[mysqld]
autocommit=0

注意

关闭自动提交以后,手动提交,其他窗口仍看不到数据变化,需要退出!!

4.2 事务演示

准备下环境,先建个counts表,插入一些初始数据。

mysql> CREATE TABLE counts(id int, name varchar(10), money int);
mysql> INSERT INTO counts(id,name,money) VALUES(1,'zhangsan',900),(2,'lisi',1100);
  • 成功事务
mysql> BEGIN;
mysql> UPDATE counts SET money=1000 WHERE name='zhangsan';
mysql> UPDATE counts SET money=1000 WHERE name='lisi';
mysql> COMMIT;
  • 事务回滚
mysql> BEGIN;
mysql> UPDATE counts SET money=1500 WHERE name='zhangsan';
mysql> UPDATE counts SET money=500 WHERE name='lisi';
mysql> ROLLBACK;

4.3 事务隐式提交情况

  • 在执行事务期间,如果执行DDL或者DCL会自动提交事务

  • 在执行事务期间,如果开启一个新事务,会自动提交上一个事务(在同一客户端)

  • 在事务运行期间,执行锁定语句(lock tables、unlock tables),也会自动提交

  • LOAD DATA INFILE

  • SELECT … FOR UPDATE

  • 在autocommit=1的时候

5.事务中的锁

5.1 事务中锁的类型

  • 共享锁(S锁、读锁):又称为读锁,允许多个连接同一时刻并发的读取同一资源,互不干扰;

  • 排他锁(X锁、写锁):又称为写锁,一个写锁会阻塞其他的写锁或读锁,保证同一时刻只有一个连接可以写入数据,同时防止其他用户对这个数据的读写。

  • 乐观锁:多事务操作,数据可以同时被修改,谁先提交以谁为准。

  • 悲观锁:多事务操作,数据只能被一个人操作。

  • 意向锁:意向锁分为意向共享锁和意向排他锁

    • 意向共享锁(IS):表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁

    • 意向排他锁(IX):类似上面,表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁。

      注意:意向锁是表级锁,其设计目的主要是为了在一个事务中揭示下一行将要被请求锁的类型。

5.2 锁的粒度

  • MyISAM:表级锁(低并发锁)

  • InnoDB:行级锁(高并发锁)

6.多版本并发控制(MVCC)

  • 只阻塞修改类操作,不阻塞查询类操作
  • 乐观锁的机制(谁先提交谁为准)

7.事务的隔离级别

7.1 脏读、不可重复读、幻读

  • 脏读:一个事务可以读取另一个尚未提交事务的修改数据。
  • 不可重复读:在同一个事务中,如果数据被其他事务修改,不能重复读取该记录原始值。
  • 幻读:在同一事务中,同一查询多次进行时候,由于其他插入操作(insert)的事务提交,导致每次返回不同的结果集。

7.2四种隔离级别

隔离级别 脏读 不可重复读 幻读
读未提交(READ UNCOMMITTED) 可能 可能 可能
读已提交(READ COMMITTED) 不可能 可能 可能
可重复读(REPEATABLE READ) 不可能 不可能 可能
可串行化(SERIALIZABLE ) 不可能 不可能 不可能
  • 读未提交(READ UNCOMMITTED)

一个事务可以读取到另一个事务未提交的修改。这会带来脏读,幻读,不可重复读问题

  • 读已提交(READ COMMITTED)

一个事务只能读取另一个事务已经提交的修改。其避免了脏读,仍然存在不可以重复读和幻读问题

  • 可重复读(REPEATABLE READ)

同一个事务中多次读取相同的数据返回的结果是一样的。其避免了脏读和不可重复读问题,但是幻读依然存在

  • 可串行化(SERIALIZABLE )

事务串行化,最高的事务隔离级别。在每个读取的数据行上加上共享锁实现,这样就避免了脏读、不可重复读和幻读等问题。但是该事务隔离级别执行效率低下,且性能开销也最大,所以一般情况下不推荐使用。

7.3 查看隔离级别

  • 查看数据库的隔离级别
mysql> SHOW VARIABLES LIKE "%iso%";
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
  • 修改隔离级别为RC(配置文件)
$ vim /etc/my.cnf
[mysqld]
transaction_isolation=read-commit