用户登录
用户注册

分享至

mysql事务隔离级别有哪些

  • 作者: 那晚越女说我?
  • 来源: 51数据库
  • 2023-02-08

事务隔离级别有四个:1、Read Uncommitted(读取未提交),允许读取尚未提交的数据变更,可能造成脏读、不可重复读、幻读。2、Read Committed(读取已提交),允许读取并发事务已经提交的数据,可以避免脏读,但是可能造成不可重复、幻读。3、Repeatable Read(可重复读取),对同一字段多次读取的结果都是一致。4、Serializable(可串行化)。

本教程操作环境:windows7系统、mysql8版本、Dell G3电脑。

一、什么是事务?

事务是逻辑上的一组操作,要么全执行,要么全不执行。

事务最经典栗子也经常被拿出来的栗子就是银行转账了。比如小明要给小红转账1000元,这个转账会涉及到两个关键操作:将小明的余额减1000元,将小红的余额减1000元。万一这两个操作之间突然出现错误,导致小明余额减少但是小红余额没有增加,这种情况是肯定不允许的。事务就是保证这两个关键操作要么都成功,要么都不成功。

二、事务的特性(ACID)

  • **原子性:**事务最小的执行单位,不允许分割。事务的原子性确保动作要么全部执行,要么全部不执行。
  • **一致性:**执行事务的前后,数据保持一致。例如转账的业务中,无论事务是否成功,转账者和收款人的总额应该是不变的。
  • **隔离性:**并发访问数据库时,一个用户的事务不应该被其他事务所影响,各并发事务之间数据库是独立的。
  • **持久性:**一个事务被提交后,它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有影响。

三、并发事务带来的问题

在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对同一数据进行操作)。并发虽然是必须的,但是可能会带来以下的问题:

  • **脏读(Dirty read):**当一个事务正在访问数据并且对其进行了修改,但是还没提交事务,这时另外一个事务也访问了这个数据,然后使用了这个数据,因为这个数据的修改还没提交到数据库,所以另外一个事务读取的数据就是“脏数据”,这种行为就是“脏读”,依据“脏数据”所做的操作可能是会出现问题的。
  • 修改丢失(Lost of modify):是指一个事务读取一个数据时,另外一个数据也访问了该数据,那么在第一个事务修改了这个数据之后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,这种情况就被称为修改丢失。例如:事务1读取表中数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果都是19,但是事务1的修改记录丢失了。
  • 不可重复读(Unrepeatableread):指在一个事务内多次读取同一数据,在这个事务还没结束时,另外一个事务也访问了这个数据并对这个数据进行了修改,那么就可能造成第一个事务两次读取的数据不一致,这种情况就被称为不可重复读。
  • 幻读(Phantom read):幻读与不可重复读类似,幻读是指一个事务读取了几行数据,这个事务还没结束,接着另外一个事务插入了一些数据,在随后的查询中,第一个事务读取到的数据就会比原本读取到的多,就好像发生了幻觉一样,所以称为幻读

不可重复读和幻读区别:

不可重复读的重点是修改,幻读的重点是新增或者删除。

栗子1(同样的条件,你读取过的数据,再次读取的时候不一样了):事务1中的A先生读取自己的工资是1000的操作还没结束,事务2的B先生就修改了A先生的工资为2000,A先生再次读取自己工资的时候就变成2000了,这就是不可重复读。

栗子2(同样的条件,第1次和第2次读取出来的记录条数不一样):假如某工资表中工资大于3000的有4人,事务1读取了所有工资大于3000的人,总共查询到4条记录,这是事务2又查询了一条工资大于3000的记录,事务1再次读取查询到的记录就是5条了,这就是幻读。

四、事务隔离级别

SQL标准定义了四个隔离级别:

  • **读取未提交(READ-UNCOMMITTED):**最低的隔离级别,允许读取尚未提交的数据变更,可能造成脏读、不可重复读、幻读。
  • **读取已提交(READ-COMMITTED):**允许读取并发事务已经提交的数据,可以避免脏读,但是可能造成不可重复、幻读。
  • **可重复读(REPEATABLE-READ):**对同一字段多次读取的结果都是一致的,除非本身事务修改,可以避免脏读和不可重复读,但是可能造成幻读。
  • **可串行化(SERIALIZABLE):**最高的隔离级别,完全服从ACID的隔离级别,所有的事务依次执行,可以避免脏读、不可重复读、幻读。
隔离级别脏读不可重复读幻读
读取未提交
读取已提交×
可重复读××
可串行化×××

MySQL InnoDB存储引擎默认的事务隔离级别是可重复读(REPEATABLE-READ),可以通过命令select @@tx_isolation;语句来查看,MySQL 8.0 该语句改为SELECT @@transaction_isolation;

mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+

MySQL InnoDB存储引擎的可重复读并不能避免幻读,需要应用使用加锁读来保证,这加锁读使用到的机制就是Next-Key Locks

因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是读取已提交(READ-COMMITTED)InnoDB 存储引擎默认使用 REPEATABLE-READ(可重读) 并不会有任何性能损失。

InnoDB存储引擎在分布式事务的情况下一般会用到可串行化隔离级别。

? 拓展一下(以下内容摘自《MySQL 技术内幕:InnoDB 存储引擎(第 2 版)》7.7 章):

InnoDB存储引擎提供了对XA事务的支持,并通过XA事务来支持分布式事务的实现。分布式事务指的是允许多个**的事务资源参与到一个全局的事务中。事务资源通常是关系型数据库系统,但也可以是其他类型的资源。全局事务要求在其中的所有参与的事务要么都提交,要么都回滚,这对事务的原有ACID要求又有了提高。另外,在使用分布式事务时,InnoDB 存储引擎的事务隔离级别必须设置为 SERIALIZABLE。

四、实际情况演示

MySQL命令行的默认配置中事务都是自动提交的,即执行SQL语句就会马上执行COMMIT操作。可以用命令START TRANSACTION开始一个事务。

我们可以通过下面命令设置事务隔离级别。

SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]

我们再来看一下我们在实际操作中使用到的一些并发控制语句:

  • START TRANSACTION | BEGIN :显示的开启一个事务。
  • COMMIT:提交事务,使得对数据库做的所有修改成为永久性。
  • ROLLBACK:回滚到结束用户的事务,并撤销正在进行的所有未提交的修改。

(脏读)读取未提交

(避免脏读)读取已提交

不可重复读

还是刚才上面的读已提交的图,虽然避免了读未提交,但是却出现了,一个事务还没有结束,就发生了 不可重复读问题。

可重复读

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ysjbfC4b-1651149978452)(https://qtspace.cn/contentimg/81.jpg)]

幻读

演示幻读出现的情况

sql 脚本 1 在第一次查询工资为 500 的记录时只有一条,sql 脚本 2 插入了一条工资为 500 的记录,提交之后;sql 脚本 1 在同一个事务中再次使用当前读查询发现出现了两条工资为 500 的记录这种就是幻读。

幻读和不可重复读有些相似之处 ,但是不可重复读的重点是修改,幻读的重点在于新增或者删除。

解决幻读的方法

  • 将事务隔离级别调整为 SERIALIZABLE
  • 在可重复读的事务级别下,给事务操作的这张表添加表锁。
  • 在可重复读的事务级别下,给事务操作的这张表添加 Next-Key Locks

说明:Next-Key Locks 相当于 行锁 + 间隙锁

【相关推荐:mysql视频教程】

以上就是mysql事务隔离级别有哪些的详细内容,更多请关注其它相关文章!

软件
前端设计
程序设计
Java相关