前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL 中的四种隔离级别

MySQL 中的四种隔离级别

作者头像
ITer.996
发布2019-08-28 10:47:42
5870
发布2019-08-28 10:47:42
举报
文章被收录于专栏:PHPer技术栈PHPer技术栈

隔离级别

数据库事务有不同的隔离级别,不同的隔离级别对锁的使用是不同的,锁的应用最终导致不同事务的隔离级别。

实现隔离级别的方式就是加锁

隔离级别的分类

代码语言:javascript
复制
读未提交 Read Uncommitted(在本次事务中可以读到其他事务中没有提交的数据 - 脏数据)

读已提交 Read Committed (只能读到其他事务提交过的数据。如果在当前事务中,其他事务有提交,则两次读取结果不同)

可重复读 Repeatable Read (默认,保证了事务中每次读取结果都相同,而不管其他事物是否已经提交。会出现幻读)

序列化 Serializable (隔离级别中最严格的,开启一个 serializable 事务,那么其他事务对数据表的写操作都会被挂起)

实验准备

首先创建一个表

代码语言:javascript
复制
account

CREATE TABLE account(

id INT NOT NULL AUTO_INCREMENT,

ACCOUNT FLOAT NOT NULL,

PRIMARY KEY(id)

)ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后插入数据

为了说明问题,我们打开两个控制台分别进行登录来模拟两个用户(暂且成为用户 A 和用户 B 吧),并设置当前 MySQL 会话的事务隔离级别。

设置事务隔离级别

设置 innodb 的事务级别方法是:set 作用域 transaction isolation level 事务隔离级别

代码语言:javascript
复制
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
mysql> set global transaction isolation level read committed; //全局的

mysql> set session transaction isolation level read committed; //当前会话

实验过程

1.read uncommitted(读取未提交数据)

代码语言:javascript
复制
A 用户
set session transaction isolation level read uncommitted;
start transaction;
select * from account;

B 用户
set session transaction isolation level read uncommitted;
start transaction;
update account set account=account+200 where id = 1;

A 用户查询

结论一:我们将事务的隔离级别设置为读未提交,所以 A 用户能够读到 B 用户没有提交的数据

存在的问题:那么这么做有什么问题吗?

那就是我们在一个事务中可以随随便便读取到其他事务未提交的数据,这还是比较麻烦的,我们叫脏读。实际上我们的数据改变了吗?答案是否定的,因为只有事务 commit 后才会更新到数据库。

2.read committed(可以读取其他事务提交的数据)--- 大多数数据库默认的隔离级别

代码语言:javascript
复制
将 B 用户的隔离级别设置为 read committed
set session transaction isolation level read committed

A 用户
start transaction;
update account set account = account-200 where id = 1; 
select * from account;

B 中
没有查询到数据的变化

在 A 中 commit 之后再在 B 中查询

结论二:我们将当前会话的隔离级别设置为 read committed 的时候,当前会话只能读取到其他事务提交的数据,未提交的数据读不到。

存在的问题:那就是我们在会话 B 同一个事务中,读取到两次不同的结果。这就造成了不可重复读,就是两次读取的结果不同。这种现象叫不可重复读。

3.repeatable read(可重读)---MySQL 默认的隔离级别

设置 B 中的隔离级别为 repeatable read

代码语言:javascript
复制
set session transaction isolation level repeatable read;

start transaction;

select * from account;

在 A 中添加一条数据

代码语言:javascript
复制
insert into account(id,account) value(3,1000);

commit;

在 B 中再查询:

用户 B 在他所在的会话中想插入一条新数据 id=3,value=1000。来我们操作下:

代码语言:javascript
复制
insert into account(id,account) value(3,5000);

发现插入不进去

结论三:当我们将当前会话的隔离级别设置为 repeatable read 的时候,当前会话可以重复读,就是每次读取的结果集都相同,而不管其他事务有没有提交。

出现的问题:

一个事务中读取的数据一致(可重复读),数据已经发生改变,但是我还是要保持一致。但是,出现了用户 B 面对的问题,这种现象叫幻读。

4.serializable(串行化)

在 B 中先开启 serializable 事务

代码语言:javascript
复制
set session transaction isolation level serializable;
start transaction;
select * from account;

然后在 A 中写数据,会出现超时,如果这时 B commmit, 那么 A 中会执行成功

结论四:当我们将当前会话的隔离级别设置为 serializable 的时候,其他会话对该表的写操作将被挂起。可以看到,这是隔离级别中最严格的,但是这样做势必对性能造成影响。所以在实际的选用上,我们要根据当前具体的情况选用合适的。

总结:

代码语言:javascript
复制
读未提交:别人修改数据的事务尚未提交,在我的事务中也能读到.
读已提交:别人修改数据的事务已经提交,在我的事务中才能读到.
可重复读:别人修改数据的事务已经提交,在我的事务中也读不到.
串行:我的事务尚未提交,别人就别想改数据.

这四种隔离级别,从上到下,并行能力依次降低,安全性一次提高.

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PHPer技术栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档