当可重复读取事务正在执行时,InnoDb-SELECT



考虑一个包含字段ID、X、Y和Z的表。

CREATE TABLE TABLE_NAME (
ID int NOT NULL,
X varchar(255) NOT NULL,
Y varchar(255) NOT NULL,
Z varchar(255) NOT NULL,
PRIMARY KEY (ID)
);
create index idx on TABLE_NAME (X, Y);

假设我有以下具有可重复读取隔离级别的事务-

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION;
SELECT * FROM TABLE_NAME WHERE X="A" AND Y="B";
INSERT INTO TABLE (ID, X, Y, Z) VALUES (25, "A", "B", "C");
INSERT INTO TABLE (ID, X, Y, Z) VALUES (26, "A", "B", "D");
DELETE FROM TABLE_NAME WHERE X="A" AND Y="B" AND (Z != "C" OR Z != "D")
COMMIT TRANSACTION;

现在假设我有一个正常的SELECT语句在事务之外执行。我想知道如果-,SELECT语句会发生什么

  1. 它在事务的SELECTINSERT之间执行
  2. 它在事务的第一个INSERT语句和第二个INSERT语句之间执行
  3. 它在事务的INSERT语句2和DELETE语句之间执行
  4. 它在DELETE语句和提交事务之间执行

我确实浏览了文档,这些是我对场景的假设-

  1. SELECT只获得一个共享锁,因此允许事务外的SELECT语句执行并查看表中所有相关的行
  2. CCD_ 12获得对新插入的行的独占锁定。允许执行事务外的SELECT语句,但它看不到新插入的行
  3. 与#2相同,允许,但它看不到两个新插入的行
  4. DELETE获得互斥锁,因此事务外的SELECT语句被阻塞,直到执行事务被提交

我的假设正确吗?这里特别混淆了#2和#3。

事务外的SELECT操作将看到TABLE,就好像事务没有发生一样。之所以如此,是因为直到COMMIT发生时事务才发生。

这就是C脱离ACID的一致性。您永远不会看到部分事务,只会看到已完成的事务(暂时忽略READ UNCOMMITED(非(隔离(。

MVCC表示先前状态可用。一旦在不同的并发事务中开始修改表的同一行,就会出现死锁或锁等待。

提交前以x、y、z为主密钥的SHOW ENGINE INNODB STATUSG示例:

------------
TRANSACTIONS
------------
Trx id counter 25
Purge done for trx's n:o < 22 undo n:o < 0 state: running but idle
History list length 4
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 20, ACTIVE 58 sec
2 lock struct(s), heap size 1128, 3 row lock(s), undo log entries 4
MariaDB thread id 3, OS thread handle 140131094689344, query id 13 localhost dan 
Trx read view will not see trx with id >= 20, sees < 20

如果在这一点上我可以在一个新的会话:

MariaDB [test]> select * from t;
Empty set (0.001 sec)

没有发生阻塞锁,可以观察到事务开始之前的状态。

另一种可视化InnoDB操作的方法:

当事务启动(或语句以autocommit=ON开头(时,将获取整个数据库的快照。事务在运行时只能看到该快照。当它完成时,所做的所有更改都是永久性的(COMMIT(或抛出的(ROLLBACK(。

现在来了解一下如何高效地拍摄如此大规模的"快照"的一些细节。每一行都有一个数字,表示它是何时创建的。同时,当另一个事务启动时,会获取类似的编号,从而定义其快照。任何早于该数字的行都可以在READ COMMITTED中看到。所有行,甚至是较新的行,对READ_UNCOMMITTED都是可见的。

啊,但这意味着每一行都可能是该行的一组版本。例如,尚未提交的UPDATE在所谓的"提交"中具有该行的至少2个副本;历史列表";。

我猜REPEATABLE_READSELECT开始时获取号码,可能比事务开始时晚?

COMMITROLLBACK时间,已修改行的历史列表将被清理。这种情况(我认为(发生在客户端被告知提交/回滚完成之后。

最新更新