1.事务的四大特性
1.原子性(Atomicity)

    事务是一个不可分割的单位,事务中的操作要么全部成功,要么全部失败。

2.一致性(Consistency)

    事务必须使数据库从一个一致性状态转变到另一个一致性状态;举个例子:A和B的总额为2000,无论他们之间如何转账,他们的总金额必须不变,这就是一致性。

3.隔离性(isolation)

    多个用户并发访问数据库时,数据库为每个用户开启事务,不会被其他事务操作所影响,多个并发事务操作互相隔离。这个隔离性有四种级别。

4.持久性(Durability)

    持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

2.并发事务可能出现的问题
2.1.脏读

    事务A读取了事务B更新的数据,然后事务B回滚了,那么事务A读取的数据是脏数据,因为事务A读取了事务B未提交的数据。

2.2.不可重复读
   

    事务A多次读取同一个数据,但是事务B在事务A的读取间隙更新并提交了数据,导致事务A读取结果不一致。

2.3.幻读

    这里经常会和不可重复读弄混淆,首先明白一点幻读并不是说“一个事务内进行两次相同操作居然得到了不一样的结果” 直接从例子入手:

T1: select * from test where id=1;

T2: insert into test(id,name) values(1,“A”) ;

T1: insert into test(id,name) values(1,“A”) ;

T1:检索id=1的数据,发现没有,插入。

T2:干扰T1事务的进行,在T1事务插入数据之前,先插入数据提交。

T1:此时T1插入数据,会报主键冲突。

    对于T1来说第一次的查询并不能支持插入操作,但实际上是可以的,T1这里就是发生了幻读,数据就像凭空出现的一样。

    所以 mysql 的幻读并非什么读取两次返回结果集不同,而是事务在插入事先检测不存在的记录时,惊奇的发现这些数据已经存在了,之前的检测读获取到的数据如同鬼影一般。

    这里要灵活的理解读取的意思,第一次select是读取,第二次的 insert 其实也属于隐式的读取,只不过是在 mysql 的机制中读取的,插入数据也是要先读取一下有没有主键冲突才能决定是否执行插入。

不可重复读侧重表达 读-读,幻读则是说 读-写,用写来证实读的是鬼影。

3.事务的隔离级别
3.1.读未提交(read uncommitted)

    可以读取未提交的数据,会出现上面的脏读现象(此隔离级别不会使用,不做解释)

3.2.读已提交(read committed)

    不能读取未提交的数据,这里就防止了脏读现象,但是避免不了不可重复读

时间    事务A    事务B
T1    开始事务    
T2        开始事务
T3        查询余额1000
T4    查询余额1000    
T5        取出1000,余额0
T6        提交
T7    查询余额0    
T8    提交    
从上面我们可以看出事务A什么都没做 只是查询了两次数据,余额就从1000变成0

3.3.可重复读(repeatable-read)(MySQL/InnoDB下的默认级别)

    针对当前读,RR隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),不存在幻读现象。

3.4.串行化(serializable)

    从MVCC并发控制退化为基于锁的并发控制。不区别快照读与当前读,所有的读操作均为当前读,读加读锁 (S锁),写加写锁 (X锁)。

    Serializable隔离级别下,读写冲突,因此并发度急剧下降,在MySQL/InnoDB下不建议使用。

 

幻读:事务A执行了一次读操作,此时事务B在事务A的影响区间内插入了一条数据,此时事务A在执行一次读操作时,会发现出现了不合理的数据。

4.Gap Lock

间隙锁,是在索引的间隙之间加上锁,这是为什么Repeatable Read隔离级别下能防止幻读的主要原因。

5、间歇锁具体例子: