选择遗忘|以及悲观锁和乐观锁的原理和应用场景,MySQL支持的事务隔离级别

关注公众号“码农架构”
专注于高可用、高性能、高并发类技术分享!
在日常开发中 , 尤其是业务开发 , 少不了利用Java对数据库进行基本的持久化的增删改查等数据操作 , 这也是Java工程师的必备技能之一 。 做好数据操作 , 不仅仅需要对Java语言相关框架的掌握 , 更需要对各种数据库自身体系结构的理解 。
如果面试时候面试官问你:MySQL支持的事务隔离级别 , 以及悲观锁和乐观锁的原理和应用场景?
典型回答
所谓隔离级别(IsolationLevel) , 就是在数据库事务中 , 为保证并发数据读写的正确性而提出的定义 , 它并不是MySQL专有的概念 , 而是源于ANSI/ISO制定的SQL-92标准 。
每种关系型数据库都提供了各自特色的隔离级别实现 , 虽然在通常的定义中是以锁为实现单元 , 但实际的实现千差万别 。 以最常见的MySQLInnoDB引擎为例 , 它是基于MVCC(Multi-VersioningConcurrencyControl)和锁的复合实现 , 按照隔离程度从低到高 , MySQL事务隔离级别分为四个不同层次:
读未提交(Readuncommitted) , 就是一个事务能够看到其他事务尚未提交的修改 , 这是最低的隔离水平 , 允许脏读出现 。 读已提交(Readcommitted) , 事务能够看到的数据都是其他事务已经提交的修改 , 也就是保证不会看到任何中间性状态 , 当然脏读也不会出现 。 读已提交仍然是比较低级别的隔离 , 并不保证再次读取时能够获取同样的数据 , 也就是允许其他事务并发修改数据 , 允许不可重复读和幻象读(PhantomRead)出现 。 可重复读(Repeatablereads) , 保证同一个事务中多次读取的数据是一致的 , 这是MySQLInnoDB引擎的默认隔离级别 , 但是和一些其他数据库实现不同的是 , 可以简单认为MySQL在可重复读级别不会出现幻象读 。 串行化(Serializable) , 并发事务之间是串行化的 , 通常意味着读取需要获取共享读锁 , 更新需要获取排他写锁 , 如果SQL使用WHERE语句 , 还会获取区间锁(MySQL以GAP锁形式实现 , 可重复读级别中默认也会使用) , 这是最高的隔离级别 。至于悲观锁和乐观锁 , 也并不是MySQL或者数据库中独有的概念 , 而是并发编程的基本概念 。
主要区别在于 , 操作共享数据时 , “悲观锁”即认为数据出现冲突的可能性更大 , 而“乐观锁”则是认为大部分情况不会出现冲突 , 进而决定是否采取排他性措施 。反映到MySQL数据库应用开发中 , 悲观锁一般就是利用类似SELECT…FORUPDATE这样的语句 , 对数据加锁 , 避免其他事务意外修改数据 。 乐观锁则与Java并发包中的AtomicFieldUpdater类似 , 也是利用CAS机制 , 并不会对数据加锁 , 而是通过对比数据的时间戳或者版本号 , 来实现乐观锁需要的版本判断 。
分析
这个问题来源于实际面试 , 这两部分问题反映了面试官试图考察面试者在日常应用开发中 , 是否学习或者思考过数据库内部的机制 , 是否了解并发相关的基础概念和实践 。
其他可以考察的点也有很多 , 在准备这个问题时你也可以对比Java语言的并发机制 , 进行深入理解 , 例如 , 随着隔离级别从低到高 , 竞争性(Contention)逐渐增强 , 随之而来的代价同样是性能和扩展性的下降 。
数据库衍生出很多不同的职责方向:
数据库管理员(DBA) , 这是一个单独的专业领域 。 数据库应用工程师 , 很多业务开发者就是这种定位 , 综合利用数据库和其他编程语言等技能 , 开发业务应用 。 数据库工程师 , 更加侧重于开发数据库、数据库中间件等基础软件 。后面两者与Java开发更加相关 , 但是需要的知识和技能是不同的 , 所以面试的考察角度也有区别 , 今天我会分析下对相关知识学习和准备面试的看法 。
另外 , 在数据库相关领域 , Java工程师最常接触到的就是O/RMapping框架或者类似的数据库交互类库 , 我会选取最广泛使用的框架进行对比和分析 。