示例MySQL事务隔离级别以及脏读、幻读、不可重复读

示例MySQL事务隔离级别以及脏读、幻读、不可重复读

浏览次数:1340次
信息来源: 银河系资源网
更新日期: 2022-05-14
文章简介

(免费):mysql教程事务的隔离性MySQL是一个客户端/服务器架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就可以称之为一个会话(Session)。每个客户端都可以在自...

(免费):mysql教程

事务的隔离性

MySQL是一个客户端/服务器架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就可以称之为一个会话(Session)。每个客户端都可以在自己的会话中向服务器发出请求语句,一个请求语句可能是某个事务的一部分,也就是对于服务器来说可能同时处理多个事务。当数据库上有多个事务同时执行的时候,就可能出现脏读(Dirty Read)、不可重复读(Non-Repeatable Read)、幻读(Phantom Read)的问题,为了解决这些问题,就有了 “隔离级别” 的概念。

理论上在某个事务对某个数据进行访问时,其他事务应该进行排队,当该事务提交之后,其他事务才可以继续访问这个数据。但一般情况下隔离得越严实,效率就会越低。因此很多时候,我们都要在隔离性和效率二者之间寻找一个平衡点。

事务并发执行遇到的问题

脏读(Dirty Read): 脏读是指一个事务读到了另一个未提交事务修改过的数据。

如小王的账户中有100的余额,接下来有两个事务对小王的账户进行访问。

会话A会话B
begin;
update xxx set balance = balance+50 where client_no = ‘小王客户号’ ;begin;

select balance from xxx where client_no = ‘小王客户号’ ;
(如果读到150,则意味着发生了脏读)
rollback;commit;

如上,会话A和会话B各开启了一个事务,会话A先给小王账户余额加了50,此时账户B查询小王账户余额为150,接下来会话A进行了回滚,那会话B查询到的150就成一个不正确的脏数据。

不可重复读(Non-Repeatable Read): 不可重复读是指在同一个事务内多次读取同一数据集合,但查到的结果却不相同。发生不可重复读的原因是在多次搜索期间查询的数据被其它事务修改了。

看如下的两个会话请求。

会话A会话B
begin;
select balance from xxx where client_no = ‘小王客户号’ ;
(读到余额为100)
begin;

update xxx set balance = balance+50 where client_no = ‘小王客户号’ ;

commit;
select balance from xxx where client_no = ‘小王客户号’ ;
(如果读到150,则意味着发生了不可重复读)

commit;

在会话A的同一个事务中,两次相同查询的结果不同,意味着发生了不可重复读。

幻读(Phantom Read): 所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会读取到之前没有读到的数据。

假如账户表中目前只有小王的余额为100,再看下如下的两个会话请求。

会话A会话B
begin;
select name from xxx where balance = 100 ;
(读到name为‘小王’)
begin;

insert into xxx(client_no,name,balance) values(‘小张客户号’,‘小张’,100);

commit;
select name from xxx where balance = 100 ;
(如果读到了‘小王’和‘小张’,则意味着发生了幻读)

commit;

会话A事务中的第二次查询,查到了第一次查询没有查到的 name ‘小张’,这就意味着出现了幻读。

SQL标准制定的四种隔离级别

ISO 和 ANIS SQL 标准制定了四种事务隔离级别的标准,分别为:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )。

我们先来看下这四种隔离级别的意思。

  • 读未提交: 一个事务还没提交时,它做的变更就能被别的事务看到。
  • 读提交: 一个事务提交之后,它做的变更才会被其他事务看到。
  • 可重复读: 一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交的变更对其他事务也是不可见的。
  • 串行化: 顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

SQL 标准中规定,针对不同的隔离级别,并发事务可以发生不同严重程度的问题,具体情况如下:
( √ 表示可以发生;× 表示不可以发生)

隔离级别脏读不可重复读幻读
读未提交(read uncommitted)
读提交(read committed)×
可重复读(repeatable read)××
串行化(serializable )×××

MySQL对四种隔离级别的支持情况

虽然 ISO 和 ANIS SQL 标准制定了四种事务隔离级别的标准,但不是所有数据库厂商都遵循这些标准,比如 Oracle 数据库就不支持读未提交(read uncommitted)和可重复读(repeatable read)的事务隔离级别。

MySQL InnoDB 存储引擎支持4种隔离级别,但与 SQL 标准中定义的不同的是,InnoDB 存储引擎在默认的可重复读(repeatable read)事务隔离级别下,使用 Next-Key Lock 锁的算法,避免了幻读的产生。也就是说 InnoDB 存储引擎在可重复读(repeatable read)的事务隔离级别下,已经可以完全保证事务的隔离性要求,即达到了 SQL 标准中的串行化(serializable )隔离级别的要求。

如何设置事务的隔离级别

在 InnoDB 存储引擎中,可以使用以下命令来设置全局或者当前会话的事务隔离级别:

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

如想设置当前会话的隔离级别为读提交,可以使用如下语句:

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

如果想在 MySQL 数据库启动时就设置事务的默认隔离级别,那就需要修改配置文件中 transaction-isolation 的值,比方说,我们在启动前指定了 transaction-isolation = READ COMMITTED,那么事务的默认隔离级别就从原来的 REPEATABLE READ 变成了READ COMMITTED。

查看当前会话的事务隔离级别,可以用如下语句:

SELECT @@transaction_isolation;

查看全局的事务隔离级别,可以使用如下语句:

SELECT @@global.transaction_isolation;

注意:transaction_isolation 是在 MySQL 5.7.20 的版本中引入来替换tx_isolation的,如果你使用的是之前版本的 MySQL,请将上述用到的 transaction_isolation 的地方替换为 tx_isolation 。

编程!!

以上就是示例MySQL事务隔离级别以及脏读、幻读、不可重复读的详细内容

标签: 暂无标签
mysql如何测试数据库是否连接成功
« 上一篇
看看MySQL并发参数调整
下一篇 »
  • oracle怎么查询数据库中的所有表名
    811124阅读
    查询方法:1、使用“SELECT * FROM all_tables WHERE OWNER = '用户名'”语句,可查询指定用户的所有表名;2、使用“SELECT * FROM user_tables”语句,可查询当前用户的所有表名。本教程操作环境:Windows7...
  • 总结MySQL常见错误分析与解决方法
    79849阅读
    免费学习:mysql教程一、Can’t connect to MySQL server on ‘localhost’ (10061) 翻译:不能连接到 localhost 上的mysql 分析:这说明“localhost”计算机是存在的,但在这台机器上却没提供MySQL服务。 需要启动这...
  • mysql怎么查询第一列数据
    2470阅读
    在mysql中,可以利用SELECT语句来查询第一列数据,该语句可以根据指定列的字段名来查询数据并输出结果,只需要将“SELECT”关键字后面的字段名设置为需要查找的第一列字段名即可; 语法“SELECT 第一列字段名 FROM 表...
  • oracle怎么查询clob字段数据
    1863阅读
    在oracle中,可以利用instr()函数配合select语句查询clob字段数据,instr函数用于判断字符串是否含有指定的字符,语法为“select*from 表名 ...instr(字段名(clod类型),'查询条件',1,1)”。本教程操作环境:...
  • mysql主从同步如何跳过错误
    1806阅读
    mysql主从同步跳过错误的方法:1、跳过指定数量的事务,代码为【mysql>SET GLOBAL SQL_SLAVE_SKIP..】;2、修改mysql的配置文件,通过【slave_skip_errors】参数来跳所有错误。本教程操作环境:windows7系统、mysql ...
  • oracle怎么判断数据是否是数字类型
    1659阅读
    方法:1、利用“trim(translate(column,'0123456789',' ')) is NULL;”判断数据是否是数字;2、利用“regexp_like(column,'^[0-9]+[0-9]$');”判断数据是否是数字。本教程操作环境:Windows...
  • mysql workbench是什么意思
    1653阅读
    mysql workbench是管理MySQL数据库工具的意思,是一款专门为mysql设计的集成化桌面软件;该软件同时具有开源社区版和收费商业版两个版本,主要用于设计和创建新的数据库图示、建立数据库文档以及进行复杂的mysql迁移...
  • 实例详解oracle添加唯一约束
    1622阅读
    本篇文章给大家带来了关于Oracle的知识,其中主要介绍了添加唯一约束的问题,唯一性约束指表中一个字段或者多个字段联合起来可以唯一标识一条记录的约束,下面一起来看一下,希望对大家有帮助。教程:《Oracle教程》...
  • MySQL索引给拿捏住了
    1578阅读
    本篇文章给大家带来了关于mysql的知识,其中主要介绍了关于mysql索引的问题,包括了索引按照逻辑功能划分、按照物理实现划分、按照字段个数划分等索引类型问题,希望对大家有帮助。学习:mysql教程在 SQL 优化中,索...
  • oracle怎么将时间日期转换成时间戳
    1518阅读
    转换方法:1、使用to_char()函数,可将时间日期按照指定的格式输出,得到的是字符串,语法“to_char(日期,"转换格式")”;2、使用to_date()函数,语法“to_date("时间字符串","转换的时间日期格式")”。本教程操作环...

如本文对您有帮助,随意赞赏一下!