事务ACID
原子性(Atomicity):当前事务的操作要么同时成功,要么同时失败。原子性由undo log日志来实现
一致性(Consistency):使用事务的最终目的,由其它3个特性以及业务代码正确逻辑来实现
隔离性(Isolation):在事务并发执行时,他们内部的操作不能互相干扰,隔离性由MySQL的各种锁以及MVCC机制来实现
持久性(Durability):一旦提交了事务,它对数据库的改变就应该是永久性的。持久性由redo log日志来实现
持久性通过redo日志来保证
用户把name改为aa,先在内存把name改为aa,然后磁盘顺序写入redo log中name=aa。然后有空的时候,线程会把内存的name=aa写入磁盘的ibd文件中,即把磁盘中的name改为aa。
这样是为了性能,总不能用户一改name,就直接随机写入ibd中吧,老慢了。ibd是随机写,磁盘redo log是顺序写比较快。
如果内存崩了,那就磁盘redo log写入ibd,这样保证了持久性。
并发带来的问题(多个人同时操作同一数据带来的问题)
- lost update 更新失效。我的更新被别人覆盖。
解决方法:加排他锁 、read uncommited 读未提交。
- dirty read脏读。我读到别人还没提交的数据。
解决办法:read commited 读已经提交
- non-repeatable read不可重复读。我每次读取的数据都要一样,不管其他人有没有刷新该数据,要可重复读,多用于报表(这个看需求,有的就需要可重复读,有的不需要,如就要看最新数据,那就是rc级别而不是这个rr级别) 。
解决办法:repeatable read 可重复读,生成快照。
- phantom read幻读。我不要读到别人新增的数据,我之外的其他人的任何操作都不要影响到我。
解决办法:serializable 串行,读加读锁。
注意:
2、3、4都是侧重于读取方面的需求,1是侧重于更新(写)方面的需求
mysql的隔离是通过锁和mvcc来实现的
mysql默认隔离级别是repeatable read
mysql的读取(select)操作是可以加锁的:
share共享锁,s锁,读锁。其他可以读取,不能增删改。如何触发读锁,select ... lock in share mode
exclude排他锁,x锁,写锁。不能读取,不能增删改。如何触发写锁,select ... for update
mvcc(Multi-Version Concurrency Control 多版本并发控制)都有啥?
- select是快照读(读历史的,事务开启时刻的),insert、update、delete是当前读(读最新的,这样才能在最新的数据上做更新,就不会在老数据上做更新了)
- select的时候会生成快照:
rc和rr的快照范围不同。rc是在同一个事务中,每个select语句都重新生成快照(语句级快照)
rr是在事务开始时或者当前数据被自己数据更改时生成快照(事务级快照)
- 快照需要undo log来实现:
如下图,事务A和事务B是在事务tx_id=2之后,tx_id=3之前开始的,三条select语句的发生时间分别是自己事务tx_id=A/B、tx_id=3、tx_id=4。