事务
什么是事务?
事务是逻辑上的一组操作,要么都执行,要么都不执行
事务特性?
- 原子性:事务执行的最小单位,不允许分割
- 一致性:执行事务前后,数据保持一致
- 隔离性:并发访问数据库时,一个用户的事务不被其他事务所打扰
- 持久性:一个事务提交之后,改变是永久的
并发事务带来的问题?
- 脏读:当一个事务修改了数据,但是没有提交事务,另一个事务读到了这个修改的数据。
- 丢失修改:A读到了数据,B也读到了数据,A修改了数据,B也修改了数据。这样造成A修改的数据丢失
- 不可重复读:一个事务内,两次查询数据的结果不一样
- 幻读:一个事务内,两次查询数据的结果不一样
不可重复读和幻读的区别?
- 不可重复读:重点在于一条记录的修改
- 幻读:重点在于新增或删除,也就是数据条数不一样
事务隔离级别?
- read-uncommitted(读取未提交):可以会导致,脏读、幻读、不可重复读
- read-committed(读已提交):可以阻止脏读,但是幻读和不可重复读让有可能发生
- repeatable-read(可重复读):可以阻止脏读和不可重复读,但是幻读让有可能发生
- serializable(可串行话:可以防止脏读、不可重复读、幻读
锁
MySQL通过锁,来解决并发事务带来的问题。
- record lock:记录锁,单个行记录上锁
- Gap lock:间隙锁,锁定一个范围,不包括记录本身
- Next-key lock:record+gap 临键锁,锁定一个范围,包含记录本身
在事务隔离级别不同的时候,使用不同的锁。
- 可以使用record lock解决脏读、不可重复读。
- 可以使用next-key lock解决幻读
MVCC(Multiversion concurrency control 多版本并发控制)
并发访问(读或写)数据库时,对正在事务内处理的数据做 多版本的管理。以达到用来避免写操作的堵塞,从而引发读操作的并发问题。
mysql表,自动带了3个隐藏字段,DB_TRX_ID(创建时事务id)、DB_ROLL_PT(删除事务id)、ROW_ID
插入
新增一条记录 ,并将 DB_TRX_ID 值设置为事务ID
删除
删除这条记录,并将 DB_ROLL_PT 值设置为事务ID
修改
修改操作是先将命中的数据行cope一个新行,将原行数据的删除版本号的值设置为当前事务ID ,新行的DB_TRX_ID设置为当前事务ID
查询
查询到的数据,创建时事务id和删除的事务id都小于当前事务id
快照读
- SQL读取的数据是快照版本,也就是历史版本,普通的SELECT就是快照读
- innodb快照读,数据的读取将由 cache(原本数据) + undo(事务修改过的数据) 两部分组成
当前读
- SQL读取的数据是最新版本。通过锁机制来保证读取的数据无法通过其他事务进行修改
- UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE都是 当前读
InnoDB通过MVCC+Next-Key lock防止幻读
1. 执行普通select,此时会以MVCC快照读的方式读取数据
在快照读的情况下,RR 隔离级别只会在事务开启后的第一次查询生成 Read View ,并使用至事务提交。所以在生成 Read View 之后其它事务所做的更新、插入记录版本对当前事务并不可见,实现了可重复读和防止快照读下的 “幻读”
2. 执行 select...for update/lock in share mode、insert、update、delete 等当前读
在当前读下,读取的都是最新的数据,如果其它事务有插入新的记录,并且刚好在当前事务查询范围内,就会产生幻读!InnoDB 使用 Next-key Lock 来防止这种情况。当执行当前读时,会锁定读取到的记录的同时,锁定它们的间隙,防止其它事务在查询范围内插入数据。只要我不让你插入,就不会发生幻读