MySQL事务机制!
MySQL事务机制!
月伴飞鱼ACID
原子性(atomicity):
- 指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。
一致性(consistency):
- 指事务执行前后,数据从一个合法性状态变换到另外一个合法性状态。
- 这种状态是语义上的而不是语法上的,跟具体的业务有关。
隔离型(isolation):
- 指一个事务的执行不能被其他事务干扰。
- 即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability):
- 指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,其他操作和数据库故障不应该对其有任何影响。
数据并发产生的问题
丢失更新(Lost Update)
- 两个事务 Session A、Session B,如果事务Session A 修改了另一个未提交事务Session B 修改过的数据,意味着发生了丢失更新。
脏读( Dirty Read ):
- 两个事务 Session A、Session B,Session A 读取了已经被 Session B 更新但还没有被提交的字段。
- 之后如果 Session B 回滚,那么Session A 读取的内容就是临时且无效的。
不可重复读( Non-Repeatable Read ):
- 两个事务Session A、Session B,Session A 读取了一个字段,然后 Session B 更新了该字段。
- 之后 Session A 再次读取同一个字段,该字段的值发生了变化。
幻读( Phantom ):
- 两个事务Session A、Session B, Session A 从一个表中读取了一个字段, 然后 Session B 在该表中插入了一些新的行。
- 如果 Session A 再次读取同一个表, 就会多出几行。
事务隔离级别
READ UNCOMMITTED(读未提交):
- 所有事务都可以看到其他未提交事务的执行结果,不能避免脏读、不可重复读、幻读。
READ COMMITTED(读已提交):
- 一个事务只能看见已经提交事务所做的改变。
- 可以避免脏读,但不可重复读、幻读问题仍然存在。
REPEATABLE READ(重复读):
- 事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,事务A再读该数据,读到的还是原来的内容。
- 可以避免脏读、不可重复读,但幻读问题仍然存在,这是MySQL的默认隔离级别。
SERIALIZABLE(可串行化):
- 确保事务可以从一个表中读取相同的行。
隔离级别 | 丢失更新 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
Read uncommitted | × | √ | √ | √ |
Read committed | × | × | √ | √ |
Repeatable read(默认) | × | × | × | √ |
Serializable | × | × | × | × |
MySQL默认隔离级别为什么是可重复读
MySQL在5.0这个版本以前,binlog只支持STATEMENT这种格式。
- 而这种格式在读已提交(Read Commited)这个隔离级别下主从复制是有bug的。
因此MSQL将可重复读(Repeatable Read)作为默认的隔离级别。
STATEMENT主从复制的Bug?
在master上执行的顺序为先删后插,而此时binlog为STATEMENT格式,它记录的顺序为先插后删。
从(slave)同步的是binglog,如果从机执行的顺序和主机不一致,就会出现主从不一致。
隔离级别设为可重复读(Repeatable Read),在该隔离级别下引入间隙锁。
当
Session 1
执行delete语句时,会锁住间隙。那么,
Ssession 2
执行插入语句就会阻塞住。保证主从复制不出问题。
为什么大家将隔离级别设为读已提交(Read Commited)
在RR隔离级别下,存在间隙锁,导致出现死锁的几率比RC大的多。
在RR隔离级别下,条件列未命中索引会锁表,而在RC隔离级别下,只锁行。
在RC隔离级别下,半一致性读(semi-consistent)特性增加了update操作的并发性。
半一致性读:
一个update语句,如果读到一行已经加锁的记录,此时InnoDB返回记录最近提交的版本。
由MySQL上层判断此版本是否满足update的where条件。
若满足(需要更新),则MySQL会重新发起一次读操作,此时会读取行的最新版本(并加锁)。
有两个Session,Session1和Session2:
Session1执行:
1 update test set color = 'blue' where color = 'red';先不Commit事务。
与此同时Ssession2执行:
1 update test set color = 'blue' where color = 'white';session 2尝试加锁的时候,发现行上已经存在锁。
InnoDB会开启semi-consistent read,返回最新的committed版本(1,red),(2,white),(5,red),(7,white)。
MySQL会重新发起一次读操作,此时会读取行的最新版本(并加锁)。
而在RR隔离级别下,Session2只能等待。
互联网项目请用:读已提交(Read Commited)这个隔离级别。
事务实现原理
原子性:使用
undo log
(回滚日志),undo log
记录了回滚需要的信息。
- 当事务执行失败或调用了
rollback
,导致事务需要回滚,便可以利用undo log
中的信息将数据回滚到修改之前的样子。隔离性: 使用悲观锁和乐观锁对事务处理。
持久性:
- 使用
redo log
(重写日志)。一致性:通过原子性、隔离性、持久性来保证一致性。
不同隔离级别,都使用了什么锁?
对于任何隔离级别,表级别的表锁、元数据锁、意向锁都是会使用的,但对于行级别的锁则会有些许差别。
在 读未提交 和 读已提交 隔离级别下,都只会使用记录锁,不会用间隙锁,当然也不会有
Next-Key
锁了。可重复读 隔离级别,会使用记录锁、间隙锁和
Next-Key
锁。