一、MySQL事务
定义:一个最小的不可再分的工作单元,通常一个事务对应一个完整的业务(如转账)。
四大特征(ACID):
原子性(A):事务是最小的单位,不可拆分。
一致性©:事务要求所有操作要么同时成功,要么同时失败。
隔离性(I):事务A和事务B之间具有隔离性。
持久性(D):事务处理结束后,对数据的修改是永久的。
操作:
开启事务:Start Transaction
结束事务:End Transaction
提交事务:Commit Transaction
回滚事务:Rollback Transaction
事务与数据库底层数据:
在事务进行过程中,未结束之前,DML语句不会更改底层数据,只是将历史操作记录一下,在内存中完成记录。只有在事务成功结束的时候,才会修改底层硬盘文件中的数据。
二、隔离级别
1、读未提交(read uncommitted):
事务A和事务B,事务A未提交的数据,事务B可以读取到,这里读取到的数据是“脏数据”,这种隔离级别最低,这种级别理论上存在,数据库隔离级别一般高于该级别。
2、读已提交(read committed):
事务A和事务B,事务A提交的数据,事务B才能读取到,对方事务提交之后的数据,我当前事务才能读取到,这种级别可避免“脏数据”,会导致“不可重复读取”,Oracle默认该级别。
3、可重复读(repeatable read):
事务A和事务B,事务A提交之后的数据,事务B读取不到,对方提交之后的数据,我还是读取不到。这种隔离级别可避免“不可重复读取”,达到可重复读取(比如1点和2点读到的数据是同一个),MySQL默认级别,可达到可重复读,会导致“幻象读”。
4、串行化(serializable):
事务A和事务B,事务A在操作数据库时,事务B只能排队等待,这种因为吞吐量太低,用户体验差,所以极少使用,这种级别可以避免“幻象读”,每一次读取的都是数据库中真实存在的数据、事务A和事务B串行而不并发。
三、解决幻读:
幻读并不是说两次获取的结果集不同,幻读侧重的方面是 某一次的select得到的结果所表示的数据状态无法支撑后续的业务操作。
如:select某记录是否存在,不存在,准备插入,但执行insert时发现此记录已经存在,无法插入,再次select还是没有该记录,此时就发生了幻读。
通过对select操作手动加锁(select…for update 这也是串行化隔离级别下隐式做的事情),即使当前记录不存在,当前事务也会获得一把记录锁(innoDb的行锁锁定的是索引,故记录是否存在没关系,存在加行锁,不存在加间隙锁),其他事务则无法插入此索引的记录,故杜绝了幻读。
InnoDb的行锁锁定的是索引,而不是记录本身,故某索引相同的记录都会被加锁,会造成索引竞争,这需要我们尽可能使用主键或唯一索引对记录加锁。索引映射的记录如果存在,加行锁,如果不存在,加间隙锁。故InnoDb可对实现事务对某记录的预先占用,无论存在与否,只要本事务还在,其他事务就别想占有他。