事务隔离性和隔离级别

事务隔离性和隔离级别隔离性是当多个用户并发访问数据库时,比如同时操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离 事务的隔离级别有哪些? 一、概念 Read uncom

事务隔离性和隔离级别

隔离性是当多个用户并发访问数据库时,比如同时操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离

事务的隔离级别有哪些?

一、概念

  • Read uncommitted(读未提交)
  • Read Committed(读已提交)
  • Repeatable Reads(可重复读)
  • Serializable(串行化)

Read uncommitted

读未提交:隔离级别最低的一种事务级别。在这种隔离级别下,会引发脏读、不可重复读和幻读。

Read Committed

读已提交读到的都是别人提交后的值。这种隔离级别下,会引发不可重复读和幻读,但避免了脏读。

Repeatable Reads

可重复读这种隔离级别下,会引发幻读,但避免了脏读、不可重复读。

Serializable

串行化是最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行。脏读、不可重复读、幻读都不会出现。

事务隔离性和隔离级别

 

 

 

二、操作

查看事务隔离级别

SHOW VARIABLES LIKE "tx_isolation";

查看全局的事务隔离级别

SHOW GLOBAL VARIABLES LIKE "tx_isolation";

使用系统变量查询

SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;

补充

MySql常用命令

    • 查询隔离级别
      select @@tx_isolation;

    • 设置手动提交
      set autocommit=0 ;

    • 查看当前事务自动提交模式
      select @@autocommit;

    • 设置隔离级别
      set tx_isolation = "READ-COMMITTED";

    • 查询表的状态
      show table status like "test1";

    • 修改表的存储引擎
      alter table test1 engine = INNODB

    • 查看是否开启日志
      show variables like "log_bin";

    • 查看日志状态
      show master status;

3.2 设置MysQL的事务隔离级别

语法

SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL

{

  REPEATABLE READ

  | READ COMMITTED

  | READ UNCOMMITTED

  | SERIALIZABLE

}

GLOBAL:设置全局的事务隔离级别
SESSION:设置当前session的事务隔离级别,如果语句没有指定GLOBAL或SESSION,默认值为SESSION

使用系统变量设置事务隔离级别

SET GLOBAL tx_isolation="REPEATABLE-READ";
SET SESSION tx_isolation="SERIALIZABLE";

 

如果并发事务没有进行隔离,会出现什么问题?

在多个事务并发做数据库操作的时候,如果没有有效的避免机制,就会出现种种问题。大体上有以下问题:

问题一:脏读

脏读指一个事务读取了另外一个事务未提交的数据。

具体看后文案例介绍

问题二:不可重复读

不可重复读指在一个事务内读取表中的某一行数据,多次读取结果不同。
不可重复读和脏读的区别是,脏读是读取前一事务未提交的脏数据,不可重复读是重新读取了前一事务已提交的数据。

具体看后文案例介绍

问题三:幻读(虚读)

幻读(虚读)指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。

以下都是采用mysql数据库

三、案例

下面实际操作中使用到的一些并发控制语句,可看上面的操作介绍

作为演示:product表(产品表)

  产品ID        产品名称        产品价格        产品数量   .

productId productName productPrice productCount
1 xiaomi 1999 100

 

带着上面的问题我们来看一下,事务在没有隔离性的情况下,会引发哪些问题?

同时打开两个窗口模拟2个用户并发访问数据库

3.1事务隔离级别设置为read uncommitted

查询事务隔离级别

SELECT @@tx_isolation; 

设置隔离级别为未提交读:

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 

注意:需要同时修改两个窗口的事务隔离级别

以下我们以两位用户抢小米手机为例

时间轴 事务A 事务B
T1 start transaction;  
T2 select p.productName,p.productCount from product p where p.productId=1;(productCount =100)  
T3   start transaction;
T4   select p.productName,p.productCount from product p where p.productId=1;(productCount =100)
T5   update product set productCount = 99 where productId = 1;
T6 select p.productName,p.productCount from product p where p.productId=1;(productCount =99)  
T7   ROLLBACK;
T8 select p.productName,p.productCount from product p where p.productId=1;(productCount =100)  

T1—— A用户开启事务,start transaction;
T2—— A用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。
T3——B用户开启事务,start transaction;
T4——B用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。
T5—— B用户购买了一台小米手机,update product set productCount = 99 where productId = 1; 此时只修改数据并未提交事务。
T6—— A用户刷新页面,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为99。
T7—— B用户购买失败,回滚事务。
T8—— A用户查询当前小米手机剩余数量,select p.productName,p.productCount from product p where p.productId=1;此时数量显示为100。

小结:

事务A读取了未提交的数据,事务B的回滚,导致了事务A的数据不一致,导致了事务A的脏读 !

3.2事务隔离级别设置为Read Committed

查询事务隔离级别

SELECT @@tx_isolation; 

更改数据库隔离级别,设置隔离级别为提交读:

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; 

注意:需要同时修改两个窗口的事务隔离级别

时间轴 事务A 事务B
T1 start transaction;  
T2 select p.productName,p.productCount from product p where p.productId=1;(productCount =100)  
T3   start transaction;
T4   select p.productName,p.productCount from product p where p.productId=1;(productCount =100)
T5   update product set productCount = 99 where productId = 1;
T7 select p.productName,p.productCount from product p where p.productId=1;(productCount =100)  
T6   commit;
T8 select p.productName,p.productCount from product p where p.productId=1;(productCount =99)  

这里就不再对流程做过多赘述。

小结:

可以看到避免了脏读现象,但是却出现了,一个事务还没有结束,就发生了不可重复读问题,即事务A来说 productCount从 100->100->99。但这个过程中事务并未提交结束。

 

3.3事务隔离级别设置为Repeatable Read(mysql默认级别)

查询事务隔离级别

SELECT @@tx_isolation; 

更改数据库隔离级别,设置隔离级别为可重复读:

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; 

注意:需要同时修改两个窗口的事务隔离级别

时间轴 事务A 事务B
T1 start transaction;  
T2 select p.productName,p.productCount from product p where p.productId=1;(productCount =100)  
T3   start transaction;
T4   select p.productName,p.productCount from product p where p.productId=1;(productCount =100)
T5   update product set productCount = 99 where productId = 1;
T7 select p.productName,p.productCount from product p where p.productId=1;(productCount =100)  
T6   commit;
T8 select p.productName,p.productCount from product p where p.productId=1;(productCount =100)  

这里就不再对流程做过多赘述。

小结:

可以看到可重复读隔离级别避免了脏读不可重复读的问题,但是出现了幻读现象。事务A查询到的小米数量等于100,但是事务B修改了数量为99,但是事务A读取到的值还是100。当事务A去减1等于99时,是错误的,此时应该是99-1=98才对。接下来我们再提高一个事务隔离级别。

3.4事务隔离级别设置为Serializable

查询事务隔离级别

SELECT @@tx_isolation; 

更改数据库隔离级别,设置隔离级别为串行化:

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; 
时间轴 事务A 事务B
T1 start transaction;  
T2   start transaction;
T2 select p.productName,p.productCount from product p where p.productId=1;(productCount =100);  
T4   update product set productCount = 99 where productId = 1;(等待中..)

这里就不再对流程做过多赘述。

小结:

在我们Serializable隔离级别中,我们可以看到事务B去做修改动作时卡主了,不能向下执行。这是因为:给事务A的select操作上了锁,所以事务B去修改值的话,就会被卡主。只有当事务A操作执行完毕,才会执行事务B的操作。这样就避免了上述三个问题了。

问题本身

  • 回到问题的本身,其实我们并不需要将事务提到这么高。

  • 问题的本身就是,当我们读完了的时候,就要在上面加锁。我们不希望别人能够去读它。因为别人读到了count,就会修改count的值,并写进去。所以我们在select 操作的时候,加上for update。这时候就会把这行操作给锁掉了。那么另外一个人也进行相同的操作,也表示select 出来的count需要进行update,需要锁住。

  • select p.productName,p.productCount from product p where p.productId=1 for update;
  • 在实际开发过程中,这样的加锁行为,是非常的耗系统性能的

本章节主要介绍了数据库中事务的ADID特性中的隔离性,在没有隔离的情况下会发生什么问题,相信大家通过本章,对数据库事务中的隔离性有了一定的了解,下篇文章我们将介绍数据库中的悲观锁与乐观锁

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/5972.html

(0)
上一篇 2023-04-20
下一篇 2023-04-20

相关推荐

  • mysql实战调优_MySQL查询优化

    mysql实战调优_MySQL查询优化前一天从自建MySQL迁移到云上RDS,在执行某个并发较高的业务时出现了大量锁等待,客户当时升级了实例到最高规格,但故障依旧。

    2023-06-03
    146
  • mysql 实战45讲_MySQL 10061

    mysql 实战45讲_MySQL 10061Mysql 一.DML-数据增删改 1. 添加 格式1:insert into 表名 (字段1,字段2….) values (值1,值2); 注意: 1、数字直接填写,非数字必须加引号(建议单引号)…

    2023-02-16
    184
  • 使用Python编写高效找到最大值的算法

    使用Python编写高效找到最大值的算法首先,我们来看一下最简单的方法:暴力比较。它的思路很简单:遍历整个列表,逐一比较每个元素,找到最大值。这种方法的时间复杂度为O(n),非常容易实现。

    2024-02-06
    97
  • Python中Scipy插值函数的使用

    Python中Scipy插值函数的使用在科学计算中,数据往往是散点的,而不是连续的函数,很多需要连续数据的应用,比如对两个数据点之间的数值进行求解,便需要使用插值函数进行处理。

    2024-04-19
    67
  • Mongodb学习总结

    Mongodb学习总结Mongodb相关操作总结

    2023-02-13
    140
  • MySQL是如何实现事务隔离?

    MySQL是如何实现事务隔离?前言 众所周知,MySQL的在RR隔离级别下查询数据,是可以保证数据不受其它事物影响,而在RC隔离级别下只要其它事物commit后,数据都会读到commit之后的数据,那么事物隔离的原理是什么?是通过

    2023-04-16
    166
  • Python卸载库指南

    Python卸载库指南Python是一门广泛使用的编程语言,每个Python用户都需要偶尔卸载库。Python库可以是Python模块、程序包和其他需要在Python中运行的文件。但当Python库不再需要或者出现问题时,卸载库是必要的。

    2024-07-19
    43
  • sql创建数据库语句_数据库建表语句

    sql创建数据库语句_数据库建表语句本文介绍如何使用 SQL INSERT 语句将数据插入到表中,如何用 INSERT SELECT 从其他表中导入行,如何用 SELECT INTO 将行导出到一个新表。 一、数据插入 毫无疑问,SEL

    2023-05-18
    155

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注