mysql持久性怎么保证 mysql怎么保证acid( 五 )


4、 在可重复读RR隔离级别下,普通查询是快照读,是不会看到别的事务插入的数据的 。因此,幻读在当前读下才会出现 。要用间隙锁解决此问题 。
在说隔离级别之前 , 你首先要知道,你隔离得越严实,效率就会越低 。因此很多时候,我们都要在二者之间寻找一个平衡点 。SQL标准的事务隔离级别由低到高如下: 上图从上到下的模式会导致系统的并行性能依次降低,安全性依次提高 。
读未提交:别人改数据的事务尚未提交 , 我在我的事务中也能读到 。
读已提交(Oracle默认):别人改数据的事务已经提交,我在我的事务中才能读到 。
可重复读(MySQL默认):别人改数据的事务已经提交,我在我的事务中也不去读,以此保证重复读一致性 。
串行:我的事务尚未提交,别人就别想改数据 。
标准跟实现:上面都是关于事务的标准 , 但是每一种数据库都有不同的实现,比如MySQL InnDB 默认为RR级别 , 但是不会出现幻读 。因为当事务A更新了所有记录的某个字段,此时事务A会获得对这个表的表锁 , 因为事务A还没有提交 , 所以事务A获得的锁没有释放,此时事务B在该表插入新记录 , 会因为无法获得该表的锁 , 则导致插入操作被阻塞 。只有事务A提交了事务后,释放了锁,事务B才能进行接下去的操作 。所以可以说 MySQL的RR级别的隔离是已经实现解决了脏读,不可重复读和幻读的 。
5、MySQL中的锁
无论是Java的并发编程还是数据库的并发操作都会涉及到锁,研发人员引入了悲观锁跟乐观锁这样一种锁的设计思想 。
悲观锁:
优点:适合在写多读少的并发环境中使用 , 虽然无法维持非常高的性能,但是在乐观锁无法提更好的性能前提下,可以做到数据的安全性
缺点:加锁会增加系统开销,虽然能保证数据的安全,但数据处理吞吐量低,不适合在读书写少的场合下使用
乐观锁:
优点:在读多写少的并发场景下,可以避免数据库加锁的开销 , 提高DAO层的响应性能,很多情况下ORM工具都有带有乐观锁的实现 , 所以这些方法不一定需要我们人为的去实现 。
缺点:在写多读少的并发场景下,即在写操作竞争激烈的情况下,会导致CAS多次重试,冲突频率过高,导致开销比悲观锁更高 。
实现:数据库层面的乐观锁其实跟CAS思想类似, 通数据版本号或者时间戳也可以实现 。
数据库并发场景主要有三种:
读-读:不存在任何问题,也不需要并发控制
读-写:有隔离性问题,可能遇到脏读 , 幻读,不可重复读
写-写:可能存更新丢失问题,比如第一类更新丢失,第二类更新丢失
两类更新丢失问题:
第一类更新丢失:事务A的事务回滚覆盖了事务B已提交的结果 第二类更新丢失:事务A的提交覆盖了事务B已提交的结果
为了合理贯彻落实锁的思想,MySQL中引入了杂七杂八的各种锁:
锁分类
MySQL支持三种层级的锁定,分别为
表级锁定
MySQL中锁定粒度最大的一种锁,最常使用的MYISAM与INNODB都支持表级锁定 。
页级锁定
是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁,表级锁速度快,但冲突多,行级冲突少,但速度慢 。所以取了折衷的页级,一次锁定相邻的一组记录 。
行级锁定
Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁 。行级锁能大大减少数据库操作的冲突 。其加锁粒度最小,但加锁的开销也最大行级锁不一定比表级锁要好:锁的粒度越细,代价越高,相比表级锁在表的头部直接加锁,行级锁还要扫描找到对应的行对其上锁,这样的代价其实是比较高的,所以表锁和行锁各有所长 。

推荐阅读