数据库中的事务是指对数据库执行一批操作,这些操作最终要么全部执行成功,要么全部失败,不会存在部分成功的情况。

事务的特性(ACID)

  • 原子性(Atomicity):一组事务,要么成功,要么撤回,事务是一个不可分割的整体, 不可能停滞在中间环节。 事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。
  • 一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。 事务开始之前、执行中、执行完毕,这些时间点,多个人去观察事务操作的数据的时候,看到的数据都是一致的
  • 隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。 比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
  • 持久性(Durability):事务提交成功后,事务对数据库的所有更新将被保存到数据库,不能回滚。

事务的并发问题

  1. 脏读:一个事务在执行的过程中读取到了其他事务还没有提交的数据。事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
  2. 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
  3. 幻读: 在一个事务的两次查询中数据笔数不一致,例如事务A查询了几列(Row)数据,而事务B却在此时插入了新的几列数据, 事务A在接下来的查询中,就会发现有几列数据是它先前所没有的

不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

MySQL事务隔离级别

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
读已提交(read-committed)
可重复读(repeatable-read)
串行化(serializable)
  1. 读未提交:一个事务可以读取到,另外一个事务尚未提交的变更。
  2. 已提交读:一个事务提交后,其变更才会被另一个事务读取到。
  3. 可重复读:在一个事务执行的过程中所读取到的数据,和事务启动时所看到的一致。
  4. 串行化:当操作一行数据时,读写分别都会加锁。当出现读写锁互斥时,会排队串行执行。

MySQL默认的事务隔离级别为可重复读(repeatable-read)

4种隔离级别越来越强,会导致数据库的并发性也越来越低。

设置事务隔离级别

  1. 配置文件my.cnf [mysqld]段中设置
1
transaction-isolation = {READ-UNCOMMITTED | READ-COMMITTED | REPEATABLE-READ | SERIALIZABLE}
  1. 命令行选项–transaction-isolation设置
  2. SET TRANSACTION语句改变单个session
1
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

查看事务隔离级别

1
2
3
4
SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
SHOW VARIABLES LIKE 'transaction_isolation';

事务操作

MySQL中事务默认是隐式事务,由变量autocommit控制,开启隐式事务操作自动提交;

隐式事务

  1. 配置文件[mysqld]设置autocommit=1或者命令行设置
1
2
set @@global.autocommit=1;
set @@session.autocommit=1;

显示事务

显示事务需要手动开启、提交、回滚

  1. set autocommit=0; // 设置不自动提交事务
  2. begin; // 开启事务
  3. start transaction; // 存储过程中begin关键字有冲突,使用这个开启事务
  4. commit; // 提交操作
  5. rollback; // 回滚操作

savepoint

在事务中设置保存点,可以将事务分为几个部分,这样能实现回滚指定部分事务

1
SAVEPOINT identifier

设置保存点,id重复设置会覆盖

1
RELEASE SAVEPOINT identifier

释放已经设置的保存点,保存点不存在时报错,重复释放同一个保存点会报错

1
ROLLBACK [WORK] TO [SAVEPOINT] identifier

回滚到指定的保存点,在保存点到当前的所有操作会回滚,保存点之前的操作依然可以提交,保存点不存在会报错

只读事务

只读事务过程中只能做只读操作,不能做DML等操作,否则报错;

1
start transaction read only;

参考