发布时间:2023-11-27 18:00
MySql 数据库设计了事务隔离机制、锁机制、MVCC多版本并发控制隔离机制,用一整套机制来解决多事务并发问题。
事务有四大特征:简称ACID特征
原子性(Atomicity):保证事务是一个不可分割的整体
例:支付操作必须全部完成,不能只完成一部分
一致性(Consistency):使数据库从一个一致性状态转移到另一个一致性状态
例:支付操作要么支付成功,要么支付失败。如果只成功一部分那么就要回滚(rollback)至未支付的状态
隔离性(Isolation):不同事务之间不能互相干扰
例:你支付时候别人也可以支付。你们两个支付行为不会互相影响
持久性(Durability):事务一旦提交,对于数据库中数据的改变是永久的
例:支付成功后,不能出现你拿着商品走了,商家的钱又跑到你账户上,让商家过把眼瘾的事情
更新丢失(Lost Update)或脏写
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。
多个事务对同一个数据的修改会导致数据覆盖
脏读
一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致的状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此作进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象的叫做“脏读”。
一个事务读到另一个事务修改后还未提交的数据
事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求。
不可重复读
一个事务在读取某些数据后,再次读取该数据,发现读出的数据已经发生了改变。
一个事务在两次读取同一个数据,前后结果不一致
事务A内部的相同查询语句在不同时刻读出的结果不一致,不符合隔离性
幻读
事务A读取数据后,B修改了数据。之后A再次读取数据,发现两次数据量不一样。与不可重复读类似,但表述的方向不同。不可重复读指读取的数据内容,幻读则指读取数据的行数。
事务A读取到了事务B提交的新增数据,不符合隔离性
隔离级别 脏读 不可重复读 幻读
读未提交 可能 可能 可能
读已提交 不可能 可能 可能
可重复读 不可能 不可能 可能
可串行化 不可能 不可能 不可能
读未提交:事务A可以读取到事务B还未commit的数据。可能会出现事务A读取到事务B的数据之后,事务B进行回滚,导致A的数据不正确。(脏读)
读已提交:事务A可以读取到事务B已commit的数据。也就是可能出现事务A读到一个数据,之后B事务commit修改了该数据,导致事务A读出两次数据不一致的情况。(不可重复读)
可重复读:事务A不能读取到事务B已commit的数据(MVCC多版本并发控制保证),但是MVCC只能保证无法读取到B修改的数据,但是如果B插入新的数据事务A仍然可以感知到,因此仍有幻读的问题。(幻读)
可串行化:事务A操作的时候导致事务B无法操作相同的数据。只要事务A操作,就对数据加悲观锁,导致事务B无法进行操作。只有事务A释放锁之后事务B才可以执行。
查看当前数据库的事务隔离级别
show variables like ‘tx_isolation’;
设置事务隔离级别
set tx_isolation=‘REPEATABLE-READ’;
Mysql默认的事务隔离级别:可重复读。用Spring开发程序时,如果不设置隔离级别,默认使用Mysql设置的隔离级别。
锁分类:
从锁的粒度上来区分,分为表锁和行锁
注意:无索引的行锁会升级为表锁。InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级为表锁
MyISAM | InnoDB |
---|---|
不支持事务 | 支持事务 |
锁的最小粒度为表锁 | 锁的最小粒度为行锁 |
非聚集索引 | 支持聚集索引 |
总结:MyISAM在执行查询语句SELECT前会自动给涉及的所有表加读锁。在执行update、insert、delete操作会自动给涉及的表加写锁。
InnoDB在执行查询语句SELECT时(非串行隔离级别),不会加锁(有MVCC)。但是update、insert、delete操作会加行锁。
锁优化建议
Mysql在读已提交和可重复读隔离级别下都实现了MVCC机制。
undo日志版本链是指一行数据被一个事务修改后,Mysql会保留修改前的数据作为undo回滚日志,并且使用两个隐藏字段trx_id和roll_pointer把这些undo日志串联起来形成一个历史记录版本链。
同时,在可重复读隔离级别,当事务开启之后执行任何查询sql时都会为当前事务生成一个read-view,该视图在事务结束之前都不会变化。(如果是读已提交的隔离级别则在每次执行查询sql时都会重新生成read-view)
read-view组成
read-view由执行查询时所有未提交事务的事务id,将id组成一个数组,并且和一个已创建的最大事务id组成。事务内的任何sql查询结果都需要从对应版本链中的最新顺序和read-view中的事务id进行对比,最终得到快照结果。
简化模型为:[min_trxid,…],max_trxid
根据这个模型将事务可以分为三部分
已提交事务部分:事务id < min_trxid的部分
未提交和已提交事务部分:min_trxid<=事务id<=max_trxid的部分
未开始事务:事务id>=max_trxid的部分
版本链比对规则
在进行版本链匹配时,根据以下规则确定当前版本数据是否对该事务是可见的。
注意:
MVCC机制的实现就是通过read-view机制与undo版本链比对机制,使得不同的事务会根据数据版本链比对规则读取同一条数据在版本链上的不同版本数据。