MySQL事务

文章目录

  • 什么是事务
  • 事务的提交方式
  • 事务的隔离级别
    • 如何理解隔离性
    • 隔离级别
    • 查看与设置隔离性
  • 读未提交(Read Uncommitted)
  • 读提交(Read Committed)
  • 可重复读(Repeatable Read)
  • 串行化(serializable)
  • 总结隔离级别
  • 一致性

什么是事务

事务就是一组DML语句组成,这些语句在逻辑上存在相关性,这一组DML语句要么全部成功,要么全部失败,是一个整体。MySQL提供一种机制,保证我们达到这样的效果。事务还规定不同的客户端看到的数据是不相同的

例如买票操作

假如只剩一张票时,客户端A判断票数还有时进行了买票程序后,出于某些原因阻塞了一下。在这过程中客户端B也判断票数,因为此时A在阻塞还未完成买票操作,所以此时的票数还是为1,那么B的判断自然可以通过。但B也进入到了买票程序后,这是A醒了将票买了,此时票数为0。但是由于B已经进入了程序中所以也会继续往下执行那此时的票数就会变为-1。显然这样子是不符合逻辑的

所以为了控制这种情况的发生,MySQL就提供了事务这种机制用来控制不同客户端对数据库的CRUD操作。

那么为了达到控制的效果,事务就必须具有如下几个属性:

  1. 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样
  2. 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作
  3. 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交( Read uncommitted )、读提交( read committed )、可重复读( repeatable read )和串行化( Serializable )
  4. 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失

需要注意并不是所有的数据库引擎都支持事务,InnoDB支持,MyISAM不支持

事务的提交方式

分为两种:

  1. 手动提交
  2. 自动提交

查看事务的提交方式

show variables like 'autocommit';

autocommit设为0即为手动提交,设为1即为自动提交

set  autocommit = 1/0

事务的隔离级别

如何理解隔离性

通俗理解为不同的事务之间的操作是不会互相干扰的。这就好像是你学习的过程,别人不回去关心你努力的过程只会看到你成绩一样。中间的任何操作对于其他的事务而言都不关心,只有当本次事务提交完成之后,别的事务才会关心。

当然MySQL也允许事物之间进行不同程度的干扰,而这个程度就由另一个特性去决定,隔离级别

隔离级别

在MySQL中有四种隔离级别

  1. 读未提交(Read Uncommitted):在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果。(实际中不可能使用这种隔离级别),但是相当于没有任何隔离性,也会有很多并发问题,如脏读,幻读,不可重复度等
  2. 读提交(Read Committed):该隔离级别是大多数数据库的默认的隔离级别(不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读,即一个事务执行时,如果多次select,可能得到不同的结果
  3. 可重复读(Repeatable Read):这是MySQL默认的隔离级别,它确保同一个事务,在执行中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题
  4. 串行化(serializable):这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决了幻读的问题。它在每个读的数据上面加上了共享锁,但是可能会导致超时和锁竞争

查看与设置隔离性

SELECT @@global.tx_isolation; --查看全局隔级别
SELECT @@session.tx_isolation; --查看会话(当前)全局隔级别
SELECT @@tx_isolation; --查看会话(当前)

MySQL事务_第1张图片

set 全局或当前 transaction isolation level 隔离级别;

MySQL事务_第2张图片

在启动MySQL会话时,会跟随全局的隔离级别

读未提交(Read Uncommitted)

几乎没有加锁,虽然效率高,但是问题太多,严重不建议采用

这种隔离级别下,不同事务间不需要提交都可以看到别的事务中间的操作结果

MySQL事务_第3张图片

可以看到正常情况下使用,只要一个事务操作之后,另一个事务就可以马上看到操作后的结果

这种现象就叫脏读现象

image-20230907165120061

可以看到如果不提交直接退出客户端,这种异常的事务,MySQL机制会自动回滚,回到最初时的状态。这就是MySQL的回滚机制

读提交(Read Committed)

先看现象

MySQL事务_第4张图片

可以看到一个事务在对表进行操作后,在没有提交之前,另一个事务是看不到操作结果的。只有当操作的事务提交后另一个事务才可以看到结果,并且另一个事务再也看不到被操作之前的数据了。这就是读提交的隔离级别。

而这种现象称为不可重复读。那么这个不可重复读有问题吗?

不可重复读看似非常符合逻辑,可是对于一些场景来说却是很严重的问题。举个例子:公司为了奖励员工根据员工的薪资等级去赠送不同的礼物。假设现在小王的薪资是等级2,小李负责统计每个员工的等级。有一天小王跟老板提出加薪得到了同意,但是小王的礼物依据旧等级发送,于是老板叫来了小黄负责改变小王在数据库里的薪资等级。

于是小李和小黄就开始对数据库进行操作了,他们同时并分别开始了自己的事务,但是由于小黄和小李并没有提前沟通过,小李只负责统计等级,小黄只负责改变等级。那这个时候由于小黄的操作比较快,提前改变了小王的等级。当小李去统计时统计到的是小王新的等级,因为不可重复读的原因并不知道小王的旧等级,这样发送给小王的礼物就违背了老板的意思。这种场景下不可重复读就成为了问题

根据上述的场景,引出下一个隔离级别—可重复读

可重复读(Repeatable Read)

先看现象

MySQL事务_第5张图片

可以看到一个事务在对表进行操作后,在没有提交之前,另一个事务是看不到操作结果的。即使操作的事务提交之后另一个事务仍然看不到操作的结果,只有当另一个事务也提交之后才可以看到结果。这就是可重复读的隔离级别

这样就可是很多的解决了不可重复读带来的问题,并且这也是MySQL的默认隔离等级

串行化(serializable)

对所有操作全部加锁,进行串行化,不会有问题,但是只要串行化,效率很低,几乎完全不会被采用

这种隔离级别的效果就是当一个事务在进行操作时,别的事务就会阻塞住,知道操作的事务提交后才会醒过来

总结隔离级别

  1. 其中隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个平衡点。
  2. 不可重复读的重点是修改和删除:同样的条件, 读取过的数据,再次读取出来发现值不一样了
  3. 幻读的重点在于新增:同样的条件, 第1次和第2次读出来的记录数不一样说明: mysql 默认的隔离级别是可重复读,一般情况下不要修改
  4. 上面的例子可以看出,事务也有长短事务这样的概念。事务间互相影响,指的是事务在并行执行的时候,即都没有commit的时候,影响会比较大

一致性

  1. 事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务成功提交的结果时,数据库处于一致性状态。如果系统运行发生中断,某个事务尚未完成而被迫中断,而改未完成的事务对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确(不一致)的状态。因此一致性是通过原子性来保证的。
  2. 其实一致性和用户的业务逻辑强相关,一般MySQL提供技术支持,但是一致性还是要用户业务逻辑做支撑,也就是一致性,是由用户决定的。
  3. 技术上,通过AID保证一致性

你可能感兴趣的:(MySQL,mysql,adb,数据库)