当筵意气临九霄,星离雨散不终朝。这篇文章主要讲述8年Java老鸟讲解, 事务的隔离级别,这篇很通透相关的知识,希望能为你提供帮助。
引言
之前关于事务的文章已介绍了事务的概念以及事务的四个属性(ACID),相信你对事务应该有所认识和了解。
本篇文章是关于事务的隔离性,介绍数据库提供的多种隔离级别。
数据库访问的并发性问题
所谓事务的隔离性,其实事务的这个属性是针对数据库访问的并发性问题而言的。
那何谓数据库访问的并发性问题呢?
所谓数据库访问的并发性问题是指多个事务可以同时访问数据库中的数据,而当多个事务在数据库中并发执行(同时执行)时,数据的一致性可能受到破坏,从而导致数据出现问题。
还是举上次转账那个例子吧!
假设你的账号上有 1000 元,你转账给朋友 100 元,然后又向账号汇入 100 元,请问你的账号上余额是多少?是不是太简单了,小学生都会算,当然还是 1000 元,对吧。 整个流程如下:
- 查看账号余额为 1000 元
- 转账给朋友 100 元,账号余额为 900 元
- 再查看账号余额为 900 元
- 汇入100 元到账号,账号余额为 1000 元
- 查看账号余额为 1000 元(转账查看)
- 查看账号余额为 1000 元(汇款查看)
- 转账给朋友 100 元,账号余额为 900 元
- 汇入100 元到账号,账号余额为 1100 元
其实,数据库访问的并发性问题有很多种情况,以上这种情况只是其中的一种叫更新丢失。
- 更新丢失
文章图片
那遇到这种情况怎么解决呢,其实更新丢失和多线程同步很相似,所以解决方法也是一样的,那就是对行加锁,同时只允许一个事务访问数据库。什么意思呀?很简单,就是加锁以后,两个事务即使同时访问数据库,也只允许加锁的事务先访问,另一个未加锁的在外等待,直到释放锁后才能访问数据库。这样,其实就是将并行访问数据库变成了串行访问数据库,是不是和多线程同步加同步锁一个道理呀。
- 脏读
文章图片
想一想怎么解决这个问题呢?解决办法很简单,就是在第一个事务提交前,任何其他事务不可读取其修改过的值,则可以避免该问题。
- 不可重复读
文章图片
解决办法也很简单,如果只有在修改事务完全提交之后才可以读取数据,则可以避免该问题。
- 幻象读
文章图片
解决办法就是如果在操作事务完成数据处理之前,任何其他事务都不可以添加新数据,则可避免该问题。
事务的隔离级别
为了解决以上各种数据库访问的并发性问题(更新丢失、脏读、不可重复读、幻象读),为此数据库提供了4种隔离级别。
- Read uncommitted(未授权读取、读未提交)
- Read committed(授权读取、读提交)
- Repeatable read(可重复读取)
- Serializable(序列化)
文章图片
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为 Read Committed(授权读取、读提交)。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和丢失更新这些并发性问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
悲观锁和乐观锁
大多数数据库的默认级别就是 Read committed(授权读取、读提交),比如Sql Server , Oracle。MySQL的默认隔离级别就是 Repeatable read。
虽然数据库的隔离级别可以解决大多数问题,但是灵活度较差,为此又提出了悲观锁和乐观锁的概念。
- 悲观锁
可能你会想,说了半天也没说为何叫悲观锁呀,到底悲观在哪里呀?这个问题问得很好。根据悲观锁的定义可知,当一个事务加了悲观锁,其他任何事务是不能读取或修改数据,也就是只能在外面等待,什么事也干不了,直到悲观锁被释放为止。那么,想象一下,如果有很多事务都要访问数据库(高并发的情况),加了悲观锁就意味所有事务需要排着长长的队,一个一个访问数据库,那么访问数据库的效率是不是非常低呀,你说悲观不悲观呀。
- 乐观锁
实现乐观锁一般来说有以下2种方式:
- 使用版本号
- 使用时间戳
说白了,乐观锁其实根本不是一种数据库锁机制,而是一种冲突检测机制,这种冲突检测机制是依赖软件或应用程序实现的。
那乐观锁为何乐观呀,乐观在它的并发性比悲观锁好,一个事务在修改数据时,其他事务仍然可以修改数据。
- 悲观锁与乐观锁的优缺点及使用场景
乐观锁的优点是可以保障并发性比较好,也就景数据库访问性能可以,它是依赖软件的冲突检测机制实现的,但是缺点就是并没彻底解决数据库访问的并发性问题,所以数据库的数据不是绝对安全的。它的使用场景是对数据安全性要求不高而对性能要求很高的场景,比如各种信息管理系统等。
总结
- 数据库访问的并发性问题(更新丢失、脏读、不可重复读、幻象读)会导致的数据的一致性被破坏。
- 数据库指定了4种事务的隔离级别,目的是为了解决数据库访问的并发性问题(更新丢失、脏读、不可重复读、幻象读)导致的数据的一致性被破坏。
- Read uncommitted(未授权读取、读未提交)
- Read committed(授权读取、读提交)
- Repeatable read(可重复读取) MySQL 默认隔离级别
- Serializable(序列化)
- 由于数据库的隔离级别灵活度较差,所以又有了悲观锁和乐观锁,也是用于解决数据库访问的并发性问题。
- 悲观锁
- 乐观锁
推荐阅读
- 解决Connecting to github.com 超时的问题
- 详细讲解Spring中的@Bean注解
- 程序员常犯的这些错误,你中招了没()
- 别慌,在Java面试的时候,面试官会这样问关于框架的问题()
- 用FastDFS一步步搭建文件管理系统
- Python 环境搭建
- ★推荐一款适用于SpringBoot项目的轻量级HTTP客户端框架
- #yyds干货盘点#剑指 Offer 10- I. 斐波那契数列
- 引发错误调用未定义函数ispage()