1. 原子性(Atomicity)
2. 一致性(Consistency)
3. 隔离性(Isolation)
4. 持久性(Durability)
事务的 ACID 特性概念简单,但不是很好理解,主要是因为这几个特性不是一种平级关系:
AUTOCOMMIT
MySQL 默认采用自动提交模式。也就是说,如果不显式使用 START TRANSACTION 语句来开始一个事务,那么每个
查询都会被当做一个事务自动提交。
二、并发一致性问题
在并发环境下,由于事务的隔离性很难保证,所以会产生并发一致性问题。
并发一致性问题主要有以下四种
- 丢失修改
- 数据脏读
- 幻影读
- 不可重复读
我们假设目前有两个事务,Transaction1和Transaction2,简称T1、T2 它们目前处于并发执行状态,由于隔离性不能保证的情况下,出现了以上四种情况。
首先是丢失修改,T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。其次是数据脏读,T1对数据进行修改的同时
T2对数据进行了读取,但是T1最后进行了回滚操作,但是T2读取了T1修改后的数据造成了脏读数据。然后就是幻影读,T1在对一个数据范围进行读取的时候,T2
对范围新增了数据,导致T1的读取结果与预期不一致。最后是不可重复读,T1事务对数据有两次读取操作,但在T1事务执行期间,T2事务对数据做了修改,导致T1
事务的第二次读取事务的结果和第一次不一致。
产生并发不一致性问题主要原因是破坏了事务的隔离性,解决方法是通过并发控制来保证隔离性。并发控制可以通过
封锁来实现,但是封锁操作需要用户自己控制,相当复杂。数据库管理系统提供了事务的隔离级别,让用户以一种更
轻松的方式处理并发一致性问题。
三、封锁
封锁粒度
MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
应该尽量只锁定需要修改的那部分数据,而不是所有的资源。锁定的数据量越少,发生锁争用的可能就越小,系统的
并发程度就越高。
但是加锁需要消耗资源,锁的各种操作(包括获取锁、释放锁、以及检查锁状态)都会增加系统开销。因此封锁粒度
越小,系统开销就越大。
在选择封锁粒度时,需要在锁开销和并发程度之间做一个权衡。
封锁类型
- 读写锁
- 排它锁 简写为 X 锁,又称写锁
- 共享锁 简写为 S 锁,又称读锁。
2. 意向锁
使用意向锁(Intention Locks)可以更容易地支持多粒度封锁。
在存在行级锁和表级锁的情况下,事务 T 想要对表 A 加 X 锁,就需要先检测是否有其它事务对表 A 或者表 A 中的任
意一行加了锁,那么就需要对表 A 的每一行都检测一次,这是非常耗时的。
意向锁在原来的 X/S 锁之上引入了 IX/IS,IX/IS 都是表锁,用来表示一个事务想要在表中的某个数据行上加 X 锁或 S
锁。有以下两个规定:
一个事务在获得某个数据行对象的 S 锁之前,必须先获得表的 IS 锁或者更强的锁;
一个事务在获得某个数据行对象的 X 锁之前,必须先获得表的 IX 锁。
通过引入意向锁,事务 T 想要对表 A 加 X 锁,只需要先检测是否有其它事务对表 A 加了 X/IX/S/IS 锁,如果加了就表
示有其它事务正在使用这个表或者表中某一行的锁,因此事务 T 加 X 锁失败。
总结:
首先我们知道了事务的概念:是一组具有ACID特性的操作,由于在并发环境下,事务会出现同时处理操作的现象,导致了事务的隔离性得不到保证,隔离性得不到保证就会使的
事务的一致性出错,从而导致并发一致性的一系列问题:脏读、幻读、不可重复读、丢失修改等。而解决的办法就是进行封锁,封锁有封锁粒度和封锁类型两个概念,封锁粒度有
行级锁和表级锁,封锁类型有 读写锁、意向锁,读写锁又包括了排它锁(写锁)、共享锁(读锁),最后就是对数据库表进行加锁操作是兼容性的问题。