[TOC]
# 一、事务
## 概念
事务指的是满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。
![](https://img.kancloud.cn/e2/fb/e2fb128e5bd99f7d834c35e75b9dd8f1_992x640.png)
## ACID
### 1. 原子性(Atomicity)
事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
回滚可以用回滚日志(Undo Log)来实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可。
### 2.一致性(Consistency)
数据库在事务执行前后都保持一致性状态。在一致性状态下,所有事务对同一个数据的读取结果都是相同的。
### 3. 隔离性(Isolation)
一个事务所做的修改在最终提交以前,对其它事务是不可见的。
### 4. 持久性(Durability)
一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。
系统发生奔溃可以用重做日志(Redo Log)进行恢复,从而实现持久性。与回滚日志记录数据的逻辑修改不同,重做日志记录的是数据页的物理修改。
* * *
事务的 ACID 特性概念简单,但不是很好理解,主要是因为这几个特性不是一种平级关系:
* 只有满足一致性,事务的执行结果才是正确的。
* 在无并发的情况下,事务串行执行,隔离性一定能够满足。此时只要能满足原子性,就一定能满足一致性。
* 在并发的情况下,多个事务并行执行,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。
* 事务满足持久化是为了能应对系统崩溃的情况。
![](https://img.kancloud.cn/78/bf/78bfa0d8d89c5bf6eeca574159b7486f_767x353.png)
## AUTOCOMMIT
MySQL 默认采用自动提交模式。也就是说,如果不显式使用`START TRANSACTION`语句来开始一个事务,那么每个查询操作都会被当做一个事务并自动提交。
# 二、并发一致性问题
在并发环境下,事务的隔离性很难保证,因此会出现很多并发一致性问题。
## 丢失修改
T1和 T2两个事务都对一个数据进行修改,T1先修改,T2随后修改,T2的修改覆盖了 T1的修改。
![](https://img.kancloud.cn/36/9b/369babf4b1544e68885f106d2c7ed8f2_807x425.png)
## 读脏数据
T1修改一个数据,T2随后读取这个数据。如果 T1撤销了这次修改,那么 T2读取的数据是脏数据。
![](https://img.kancloud.cn/7c/a4/7ca4d52c09032ed29a0404f5115928a2_756x623.png)
## 不可重复读
T2读取一个数据,T1对该数据做了修改。如果 T2再次读取这个数据,此时读取的结果和第一次读取的结果不同。
![](https://img.kancloud.cn/71/b5/71b5c3a0a5dddafa08916bdfd2ea2455_759x565.png)
## 幻影读
T1读取某个范围的数据,T2在这个范围内插入新的数据,T1再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。
![](https://img.kancloud.cn/32/02/3202af2521b2098a4a67f3d8ff57b6e9_1030x702.png)
产生并发不一致性问题的主要原因是破坏了事务的隔离性,解决方法是通过并发控制来保证隔离性。并发控制可以通过封锁来实现,但是封锁操作需要用户自己控制,相当复杂。数据库管理系统提供了事务的隔离级别,让用户以一种更轻松的方式处理并发一致性问题。
# 三、封锁
## 封锁粒度
MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
应该尽量只锁定需要修改的那部分数据,而不是所有的资源。锁定的数据量越少,发生锁争用的可能就越小,系统的并发程度就越高。
但是加锁需要消耗资源,锁的各种操作(包括获取锁、释放锁、以及检查锁状态)都会增加系统开销。因此封锁粒度越小,系统开销就越大。
在选择封锁粒度时,需要在锁开销和并发程度之间做一个权衡。