当另一个事务具有排他锁时,MySQL如何允许获取共享锁?

问题描述

我试图了解交易的工作方式,我遇到了一个对我来说没有多大意义的场景。我希望有人能帮助我理解它。

我有两笔交易

交易1

 BEGIN; update data set val = val + 1 where id = 1

交易2

BEGIN; select * from data

我有两个开放的终端,我开始第一个事务并运行更新查询。据说这将给ID为1的元组上的事务1排他锁。

在此之后,我在提交第一个事务之前在另一个终端中运行第二个查询。我原以为它会停滞,因为第一个事务具有排他锁,这将阻止该事务获取ID为1的元组的读取锁。

但是,mysql运行select查询并返回“不脏”数据。

有人可以给我解释这种mysql行为的原因吗?

解决方法

SELECT默认不需要共享行锁。通过使用multi-version concurrency control (MVCC) architecture,它可以读取该行的最新提交版本而不会锁定。

您可以编写SELECT query that explicitly requests a lock,但是如果没有这些锁定子句,SELECT就不需要行锁定。

,

要全面了解事务的工作原理,我认为有必要了解共享锁的获取方式不同,具体取决于隔离级别。

独占锁在事务结束时释放,与隔离级别无关。

隔离级别之间的差异是指获取/释放共享(读)锁的方式。

在 Read Uncommitted 隔离级别下,不会获取共享锁。在此隔离级别下,可能会发生称为“脏读”的并发问题。

在 Read Committed 隔离级别下,为相关记录获取共享锁。当前指令结束时,共享锁被释放。此隔离级别可防止“脏读”,但由于记录可由其他并发事务更新,因此可能会发生“不可重复读”或“幻读”。

在可重复读隔离级别下,在事务期间获取共享锁。 “脏读”和“不可重复读”被阻止,但“幻读”仍然可能发生。

在 Serializable 隔离级别下,在事务期间获取范围共享锁。上面提到的并发问题都没有发生,但性能会急剧下降,并且存在发生死锁的风险。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...