MySQL事务的隔离级别
事务的隔离级别
当数据库里有多个事务同时执行的时候,就可能会出现,幻读,脏读,不可重复读的问题,为了解决这些问题,就出现了隔离级别的概念。
读未提交:别人改数据的事务尚未提交,我在我的事务中也能读到。
读已提交:别人改数据的事务已经提交,我在我的事务中才能读到。
可重复读:别人改数据的事务已经提交,我在我的事务中也不去读。
串行:我的事务尚未提交,别人就别想改数据。
这4种隔离级别,并行性能依次降低,安全性依次提高。
我们重点说下读提交和可重复读
mysql> create table T(c int) engine=InnoDB; insert into T(c) values(1);
我们看下在不同的隔离级别下,每个查询得到的值是多少
- 读未提交:V1=2,V2=2,V3=2,因为是读未提交,所以事务B的修改V1可以看见,所以V1的值就是2,V2,V3的值肯定也是2
- 读提交:V1=1,V2=2,V3=2,因为是读提交,数据的更新只有在事务提交以后才可以被其他事务看见,在进行V1查询的时候,事务B还没提交,所以这个时候V1的值还是1,但是V2的查询是在事务B提交以后查询的,所以V2的值就是2,V3的值也是2
- 可重复读:V1=1,V2=1,V3=2,因为是可重复读,所以A事务中的查询出的数据在事务之间从头到尾都是一样的,事务A在启动的时候查询出来的值是1,所以V1和V2的值都是1,V3是在事务A提交以后进行的查询,这个时候事务B也提交了,所以查询的值V3就是2,当然在这里的事务A中的查询V1和V2用的是"快照读",所以值都是1,如果用的是当前读,比如说select c from t for update,这个时候V1的值就是2,这是什么意思呢?就是说当你是单纯的读的时候给你查询出来的值是事务一开始的数据的值,但是当你需要修改的时候,也就是当前读的时候,就需要给你最新的数据版本的值,你需要在最新版本上的数据上进行修改
- 串行化:这个隔离级别下,事务B在执行“将1改成2”这个操作时,会被锁住,要一直等到事务A提交后才可以执行,所以这个时候对于事务A来说V1,V2的值都是1,V3的值是2
是实现上,数据库会创建一个视图,这里的视图不是sql语句的那个视图,在可重复读隔离级别下,会在事务启动的时候创建一个整库数据的视图,访问的时候以这个视图里面的数据为准,读提交下会在执行一个查询语句的时候,创建这个视图,读未提交下,会直接返回最新的数据,串行化直接用加锁的方法,避免了并行,所以这两个事务没有视图的概念。
事务隔离的实现
理解了事务隔离的概念,接下来我们看看事务隔离是如何实现的,这里我们展开说明可重复读
在mysql中每进行一个变更操作都会记录一条日志,不同的视图在同一时刻看到的值是不一样的,视图A,B,C看到的值分别是1,2,4,这就是数据库的数据多版本控制(MVCC),也就是说这个时候,如果视图C,想要把值改成2,那么就要依次执行将4改成3,将3改成2,这两个操作。
那么这些回滚日志在什么时候会被删除呢?就是当系统里没有比这个回滚日志更早的视图的时候。
接下来我们说说为什么数据库里尽量不要有长事务,当有一个长事务时,意味着系统里会存在很老的视图,所以这个事务提交之前,数据库里他所有可能用到的回滚记录到必须保留。
举个例子吧:
比如,在某个时刻(今天上午9:00)开启了一个事务A(对于可重复读隔离级别,此时一个视图read-view A也创建了),这是一个很长的事务……
事务A在今天上午9:20的时候,查询了一个记录R1的一个字段f1的值为1……
今天上午9:25的时候,一个事务B(随之而来的read-view B)也被开启了,它更新了R1.f1的值为2(同时也创建了一个由2到1的回滚日志),这是一个短事务,事务随后就被commit了。
今天上午9:30的时候,一个事务C(随之而来的read-view C)也被开启了,它更新了R1.f1的值为3(同时也创建了一个由3到2的回滚日志),这是一个短事务,事务随后就被commit了。
……
到了下午3:00了,长事务A还没有commit,为了保证事务在执行期间看到的数据在前后必须是一致的,那些老的事务视图、回滚日志就必须存在了,这就占用了大量的存储空间。
源于此,我们应该尽量不要使用长事务。
事务的启动方式
如上所述长事务有这些潜在风险,所以要尽量避免长事务,其实很多时候我们都是误用导致了长事务。
MySQL的事务启动方式有以下几种
- 显式启动,begin或start transaction,对应的语句是commit,回滚语句是rollback
- set autocommit = 0,这个命令会将这个线程的自动提交关闭,意味着如果你只执行一个select语句,这个事务就启动了,而且并不会自动提交,这个事务持续存在直到你执行commit或rollback语句,或者断开连接
有些客户端框架会默认连接成功后,执行一个set autocommit = 0命令,这就导致接下来的查询都在事务中,如果是长连接就导致了长事务。
你可以在informationschema库的innodb_trx表中查询长事务,比如这个语句聚会查询出持续时间超过60s的事务
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
开发函数计算的正确姿势 —— 移植 next.js 服务端渲染框架
首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。函数计算更多信息参考。 Fun: Fun 是一个用于支持 Serverless 应用部署的工具,能帮助您便捷地管理函数计算、API 网关、日志服务等资源。它通过一个资源配置文件(template.yml),协助您进行开发、构建、部署操作。Fun 的更多文档参考。 2.0 版本的 Fun,在部署这一块做了很多努力,并提供了比较完善的功能,能够做到将云资源方便、平滑地部署到云端。但该版本,在本地开发上的体验,还有较多的工作要做。于是,我们决定推出 Fun Init 弥补这一处短板。 Fun Init: Fun Init 作为 Fun 的一个子命令存在,只要 Fun 的版本大于等于 2.7.0,即可以直接通过fun init命令使用。Fun Init 工具可以根据指定的模板快速的创建函数计算应用,快速体验和开...
- 下一篇
轻量快速的CI工具Drone快速入门
前言 公司之前一直在使用 Jenkins 作为 CI/CD 工具, Jenkins 非常强大,它完成了几乎所有 CI/CD 的工作,并且应用于整个团队有好长一段时间了。但是随着公司推荐数字化、智慧化,以及服务容器化的推进, Jenkins 的一些弊端也凸显了出来: 重量级: Jenkins 功能十分齐全,几乎可以做所有的事情。但是这也是他的一个弊端,过于重量级,有时候往往一个小的修改需要改动许多地方,升级\下载插件后需要进行重启等。 升级不易: 在一些安全 Jenkins 相关的安全漏洞被公开后,我们会对 Jenkins 进行升级,但这也不是一件容易的事。之前就出现过升级\重启后,所有 job 丢失,虽然我们所有项目配置都是以 Jenkinsfile 的形式统一存储,但是每个 job 都需要重新重新创建,包括每个 job 的权限....._(´ཀ`」 ∠)_ 权限控制复杂: 这其实也是 Jenkins 的一大优势,可以精确控制每个用户的权限,但是需要花费更多时间去配置,时间长了也会出现权限混乱的问题。 UI 界面: 这个其实是吐槽最多的部分,虽然有诸如:Blue Ocean 这样的插件...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS7设置SWAP分区,小内存服务器的救世主
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- MySQL8.0.19开启GTID主从同步CentOS8
- Linux系统CentOS6、CentOS7手动修改IP地址
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS7,8上快速安装Gitea,搭建Git服务器