1. 前言
今天看了Spring声明式事务,回看了之前相关的MySQL笔记,有了更体系化的认识,现在整理下。
2. 概念
- 锁方面的概念:MyISAM 与 InnoDB 关于锁方面的区别
- 更新丢失、脏读、不可重复读、幻读:数据库操作会产生的一致性问题
- ACID:是指数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性
- 原子性(atomicity,或称不可分割性)
- 一致性(consistency)
- 隔离性(isolation,又称独立性)
- 持久性(durability)
- 事务隔离级别的概念:来源于ACID中I的应用,用于解决C的问题,事务隔离级别与一致性问题的关系
3. 整体性认识
- 【更新丢失、脏读、不可重复读、幻读】是并发操作产生的数据不一致隐患,可能会产生业务逻辑上的bug。
- 【事务隔离级别】是数据库针对解决【更新丢失、脏读、不可重复读、幻读】的方案,这些方案背后是一系列的算法支持。事务隔离级别直接体现整体并发度。隔离级别越高,则并发度越低。
在数据一致性和并发度的追求上,我们往往有所折中,并不会采用SERIALIZABLE
牺牲所有并发度,也不会采用READ-UNCOMMITTED
暴露所有一致性隐患。那么留下来的选择就是READ-COMMITTED
和REPEATABLE-READ
,也就是常说的RC
和RR
的隔离级别。我个人觉得使用这两个隔离级别没有绝对的对错,需要根据业务场景进行综合考量。庆幸的是,我们可以暂时把只把目光放在RC
和RR
的隔离级别上。
4. 实践意义
考虑什么情况下使用RC
或RR
的隔离级,也就成为指导实践的线索。
4.1 RR隔离级别
RR级别下唯一存在的隐患就是幻读,如果能够解决幻读问题,意味着程序能够兼顾并发度和数据一致性。InnoDB 如何防止幻读。
- 幻读隐患的触发条件
- 当前读和快照读混用
- 不同事务的更新并发操作
- 消除幻读隐患可能会产生的弊端
RR下解决幻读,虽然增加了并发度也保障了数据一致性,但是容易产生死锁的可能性(TODO 这个内容比较深,目前还在了解的阶段)
4.2 RC隔离级别
RC级别下的并发度比RR高,则在另一方面,对SQL语句的书写规范有着更高的要求。值得一提的是,该级别下一定会出现幻读的隐患,如果业务上对幻读的发生是不在意的,那么可以考虑使用该级别。该级别下急切要解决的是可重复读的隐患。
- 可重复读隐患的触发条件
业务逻辑里面读取同一条记录两遍,使用ORM
的情况下,是很少单独查一个表查两遍的。但是如果出现了范围查询,很有可能会隐性得读同一条记录两遍 - 消除幻读隐患可能会产生的弊端
需要了解到,RC无法消除可重复读的隐患。
4.3 总结
如果不需要较高的并发度,使用RR
隔离级别即可。如果需要较高的并发读,在RC
级别下使用合理的编程习惯,也无大碍。关键得是程序员要在编程的时候,了解自己事务所处的隔离环境,不要轻易写出update insert
后不命中索引的锁表的语句,也不要反复先select
再update
造成一致性的隐患。