当前位置: 首页 > news >正文

MySQL——事务管理

1. 事务的概念

1. 事务由一条或者多条SQL语句组成,这些语句具有逻辑关联性,共同完成一个任务。

2. MySQL同一时刻可能存在大量事务,如果不对这些事务加以控制,在执行时就可能会出现问题。比如单个事务内部的某些SQL语句执行失败,或是多个事务同时访问同一份数据导致数据不一致的问题。

因此一个完整的事务并不是简单的SQL集合,事务还需要满足如下四个属性:

1. 原子性:一个事务中的所有操作,要么不做,要么全完成,不会结束在中间某个环节。事务在执行过程中如果发生错误,则会自动回滚到事务开始前的状态,就像这个事务从来没有执行过一样。

2. 持久性:事务处理结束后,对数据的修改是永久的,即使系统故障也不会丢失。

3. 隔离性:数据库允许多个事务访问同一份数据,隔离性可以保证多个事务在并发执行时,不会因为由于交叉执行而导致数据的不一致。

4. 一致性:在事务开始之前和事务结束以后,数据库的完整型没有被破坏,这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联型以及后续数据库可以自发性地完成预定的工作。

上面的四个属性简称ACID:

  • 原子性(Atomicity,又称不可分割性)。
  • 一致性(Consistency)。
  • 隔离性(Isolation,又称独立性)。
  • 持久性(Durability)。

为什么会出现事务?

1. 事务被MySQL编写者设计出来,本质是为了当应用程序访问数据库的时候,事务能够简化我们的编程模型,不需要用户自己去考虑各种各样的潜在错误和并发问题。

2. 如果MySQL只是单纯的提供数据存储服务,那么用户在访问数据库时就需要自行考虑各种潜在问题,包括网络异常、服务器宕机等。因此事务本质是为了应用服务的,而不是伴随着数据库系统天生就有的。

2. 事务的版本支持

通过show engines命令可以查看数据库引擎。如下:

  • Transactions: 表示存储引擎是否支持事务,可以看到InnoDB存储引擎支持事务,而MyISAM存储引擎不支持事务。

3. 事务的提交方式

事务常见的提交方式有两种,分别是自动提交和手动提交。

通过show命令查看autocommit全局变量,可以查看事务的自动提交是否被打开。如下:

autocommit的值为ON表示自动提交被打开,值为OFF表示自动提交被关闭,即事务的提交方式为手动提交。

设置事务的提交方式

通过set命令设置autocommit全局变量的值,可以打开或关闭事务的自动提交。如下:

将autocommit的值设置为1表示打开自动提交,设置为0表示关闭自动提交,相当于将事务提交方式设置为手动提交。

4. 事务的相关演示

首先我们先来做一下准备工作,为了更好地看到现象,我们要把隔离级别先设置成最低级别,即读未提交;

这里我们设置的是全局隔离级别,当前会话的隔离级别不会改变,只会影响后续与MySQL新建立的连接,因此需要重启终端才能看到会话的隔离级别被成功设置。如下:

创建一个银行用户表,表中包含用户的id、姓名和账户余额。如下:

演示一:事务的常规操作

启动两个终端,左终端使用begin或start transaction命令启动一个事务,右终端查看银行用户表中的信息。如下:

左终端中的事务向表中插入一条记录,由于我们将隔离级别设置成了读未提交,因此在左终端中的事务使用commit提交之前,在右终端中就能查看到事务向表中插入的记录。如下:

左终端中的事务使用savepoint命令创建一个保存点,然后继续向表中插入一条记录,这时在右终端中也能看到新插入的这条记录。如下:

左终端中的事务使用rollback命令回滚到保存点,这时右终端在查看表中数据时就看不到刚才插入的第二条记录了。如下:

左终端中的事务使用rollback命令回滚到事务最开始,这时右终端在查看表中数据时就看不到任何记录了。如下:

说明一下:

1. 使用begin或start transaction命令,可以启动一个事务。
2. 使用“savepoint 保存点”命令,可以在事务中创建指定名称的保存点。
3. 使用”rollback to 保存点“命令,可以让事务回滚到指定保存点。
4. 使用rollback命令,可以直接让事务回滚到最开始。
5. 使用commit命令,可以提交事务,提交事务后就不能回滚了。

演示二:原子性

在左终端中启动一个事务,在右终端查看银行用户表中的信息。如下:

左终端中的事务向表中插入一条记录,由于隔离级别是读未提交,因此在右终端中能够查询到插入的这条记录。如下:

如果左终端中的事务在提交之前因为某些原因与MySQL断开连接,那么MySQL会自动让事务回滚到最开始,这时右终端中就看不到之前插入的记录了。如下:

这里就是原子性的体现,因为我们没有对事务进行提交,那么就相当于没做这个事务,原子性就是要么不做,要么做完,没有中间状态,如果中间退出,那就相当于没做。

演示三:持久性

在左终端中启动一个事务,在右终端查看银行用户表中的信息。如下:

左终端中的事务向表中插入一条记录,由于隔离级别是读未提交,因此在右终端中能够查询到插入的这条记录。如下:

左终端中的事务在提交后与MySQL断开连接,这时右终端中仍然可以看到之前插入的记录,因为事务提交后数据就被持久化了。如下:

演示四:begin会自动更改提交方式

通过show命令查看autocommit的值为ON,表示事务的提交方式是自动提交,此时银行用户表中有一条记录。如下:

在左终端中启动一个事务并向表中新插入一条记录,由于隔离级别是读未提交,因此在右终端中能够查询到新插入的这条记录。如下:

如果左终端中的事务在提交之前与MySQL断开连接,那么MySQL依旧会自动让事务回滚到最开始,这时右终端中就看不到之前新插入的记录了。如下:

也就是说,使用begin或start transaction命令启动的事务,都必须要使用commit命令手动提交,数据才会被持久化,与是否设置autocommit无关。我们之前一直都在使用单SQL事务,只不过autocommit默认是打开的,因此单SQL事务执行后自动就被提交了。

5. 事务的隔离级别

隔离级别有四种:读提交(Read Uncommitted)、读未提交(Read Committed)、可重复读(Repeatable Read,MySQL默认隔离级别)、串行化(Serializable)

5.1 查看与设置隔离级别

查看全局隔离级别

查看会话隔离级别

说明一下:这里因为我们上面设置了全局隔离级别为RU,所以这里我们查出来的都是RU级别。

设置全局隔离级别

通过”set global transaction isolation level 隔离级别“命令,可以设置全局隔离级别。如下:

说明一下: 设置全局隔离级别会影响后续的新会话,但当前会话的隔离级别没有发生变化,如果要让当前会话的隔离级别也改变,则需要重启会话

设置会话隔离级别

通过”set session transaction isolation level 隔离级别“命令,可以设置当前会话的隔离级别。如下:

说明一下: 设置会话的隔离级别只会影响当前会话,新起的会话依旧采用全局隔离级。也就是说重启会话后,还是采用全局隔离级别,所以一般情况下,我们直接设置全局隔离级别即可。

5.2 读未提交(Read Uncommitted)

启动两个终端,将隔离级别都设置为读未提交,并查看此时银行用户表中的数据。如下:

在两个终端各自启动一个事务,左终端中的事务所作的修改在没有提交之前,右终端中的事务就已经能够看到了。如下:

说明一下:

1. 读未提交是事务的最低隔离级别,几乎没有加锁,虽然效率高,但是问题比较多,所以严重不建议使用。
2. 一个事务在执行过程中,读取到另一个执行中的事务所做的修改,但是该事务还没有进行提交,这种现象叫做脏读

5.3 读提交(Read Committed)

启动两个终端,将隔离级别都设置为读提交,并查看此时银行用户表中的数据。如下:

在两个终端各自启动一个事务,左终端中的事务所作的修改在没有提交之前,右终端中的事务无法看到。如下:

只有当左终端中的事务提交后,右终端中的事务才能看到修改后的数据。如下:

说明一下:

一个事务在执行过程中,两个相同的select查询得到了不同的数据,这种现象叫做不可重复读

5.4 可重复读(Repeatable Read)

启动两个终端,将隔离级别都设置为可重复读,并查看此时银行用户表中的数据。如下:

在两个终端各自启动一个事务,左终端中的事务所作的修改在没有提交之前,右终端中的事务无法看到。如下:

并且当左终端中的事务提交后,右终端中的事务仍然看不到修改后的数据。如下:

只有当右终端中的事务提交后再查看表中的数据,这时才能看到修改后的数据。如下:

说明一下:

1. 在可重复读隔离级别下,一个事务在执行过程中,相同的select查询得到的是相同的数据,这就是所谓的可重复读。
2. 一般的数据库在可重复读隔离级别下,update数据是满足可重复读的,但insert数据会存在幻读问题,因为隔离性是通过对数据加锁完成的,而新插入的数据原本是不存在的,因此一般的加锁无法屏蔽这类问题。
3. 一个事务在执行过程中,相同的select查询得到了新的数据,如同出现了幻觉,这种现象叫做幻读

4. MySQL是通过Next-Key锁(GAP+行锁)来解决幻读问题的。上面图中右边事务提交之前,我们是看不到表的内容发生变化的。

5.5 串行化(Serializable)

启动两个终端,将隔离级别都设置为串行化,并查看此时银行用户表中的数据。如下:

在两个终端各自启动一个事务,如果这两个事务都对表进行的是读操作,那么这两个事务可以并发执行,不会被阻塞。如下:

但如果这两个事务中有一个事务要对表进行写操作,那么这个事务就会立即被阻塞。如下:

直到访问这张表的其他事务都提交后,这个被阻塞的事务才会被唤醒,然后才能对表进行修改操作。如下:

这里大家需要注意,右边commit之后,刚才左边阻塞的操作就会立即执行完成,这时我们查看表,发现数据还是没变,这是因为左边还没commit,我们隔离级别是最高级别,所以左边必须commit之后,我们才可以看到改变后的数据。

说明一下:

串行化是事务的最高隔离级别,多个事务同时进行读操作时加的是共享锁,因此可以并发执行读操作,但一旦需要进行写操作,就会进行串行化,效率很低,几乎不会使用

5.6 隔离级别总结

说明一下:

  • 隔离级别越严格,安全性越高,但数据库的并发性能也就越低,在选择隔离级别时往往需要在两者之间找一个平衡点。
  • 表中只写出了各种隔离级别下进行读操作时是否需要加锁,因为无论哪种隔离级别,只要需要进行写操作就一定需要加锁。

6. 关于一致性

MySQL本身其实对一致性并没有做出什么措施,实际上一致性是由原子性、隔离性、持久性共同保证的。

  • 事务处理结束后,对数据的修改必须是永久的,即便系统故障也不能丢失,即一致性需要持久性来保证。
  • 多个事务同时访问同一份数据时,必须保证这多个事务在并发执行时,不会因为由于交叉执行而导致数据的不一致,即一致性需要隔离性来保证。
  • 事务在执行过程中如果发生错误,则需要自动回滚到事务最开始的状态,就像这个事务从来没有执行过一样,即一致性需要原子性来保证。
  • 此外,一致性与用户的业务逻辑强相关,如果用户本身的业务逻辑有问题,最终也会让数据库处于一种不一致的状态。

总结来说,一致性实际是数据库最终要达到的效果,一致性不仅需要原子性、持久性和隔离性来保证,还需要上层用户编写出正确的业务逻辑。

http://www.dtcms.com/a/479800.html

相关文章:

  • html5网站后台公司网站制作合同
  • 网站建设搭配网站优化成功案例
  • C++浮点数取余函数fmod()介绍
  • riscv将全局变量固定到指定的地址
  • 设计公司是建筑企业吗seo一个空间建多个网站
  • seo整站优化哪家好桂林做网站电话号码
  • 网站不备案黑龙江省特种证查询
  • 网站设计交流网站关键词优化代理
  • 【Linux在环境安装】SpringBoot应用环境安装(一)-JDK安装
  • 网站后台上传图片不显示高新建设网站电话
  • 一台服务器可以建设几个网站wordpress返回
  • 苏宁网站开发人员工资用dw做网站的视频
  • Android Jetpack 系列(七)App Startup 启动优化
  • 网站建设的收费网站建设优化开发公司
  • 【代码收藏夹·Python】使用paho连接MQTT
  • 怎么把网站排名优化秦皇岛网站建设
  • 百度推广登录平台登录泊头 网站优化
  • JS - 数据类型
  • 站长之家新网址网络营销外包有限公司
  • 未来之窗昭和仙君(十六)网页数字动画函数——东方仙盟筑基期
  • 新手怎么学习网站建设网站建设横幅
  • 怎样做简单公司网站ip代理提取网站源码
  • 【Python】从 MP4 文件中提取中英双语字幕并生成双语字幕文件(如 .srt)
  • 基于ffmpeg库,在AGX上编译jetsonFFmpeg库带有硬件加速的h264_nvmpi视频编解码器
  • wordpress熊掌号自动提交seo如何使用wordpress优化
  • 网站维护费一般多少钱湖南好搜网站建设
  • 机器人软件开发和网站开发wordpress后台登录
  • 3d演示中国空间站建造历程牡丹江建站
  • 服务器网站管理系统泰山信息科技有限公司
  • 网站备案是域名备案还是服务器备案长沙房价一览表