使用不相关的SELECT语句返回不同结果的并发MYSQL过程调用

使用不相关的SELECT语句返回不同结果的并发MYSQL过程调用,mysql,stored-procedures,transactions,mariadb,table-locking,Mysql,Stored Procedures,Transactions,Mariadb,Table Locking,我在MYSQL应用程序中遇到了一些非常奇怪的事务行为 我已经设法将问题简化为一个小的独立测试用例,下面包含了代码: -- Setup a new environment SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; DROP DATABASE IF EXISTS `testDB`; CREATE DATABASE `testDB`; USE `testDB`; -- Create a table I want two proced

我在MYSQL应用程序中遇到了一些非常奇怪的事务行为

我已经设法将问题简化为一个小的独立测试用例,下面包含了代码:

-- Setup a new environment
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
DROP DATABASE IF EXISTS `testDB`;
CREATE DATABASE `testDB`;
USE `testDB`;

-- Create a table I want two procedure calls to interact with
CREATE TABLE `tbl_test` (
    `id` INT(10) UNSIGNED NOT NULL
    , PRIMARY KEY (`id`)
);

-- A second table purely to demonstrate the issue
CREATE TABLE `tbl_test2` (
    `id` INT(10) UNSIGNED NOT NULL
);


DELIMITER $$

DROP PROCEDURE IF EXISTS `sp_test` $$
CREATE PROCEDURE `sp_test` ()
BEGIN

    START TRANSACTION;

        -- CRAZY LINE
        SELECT * FROM `tbl_test2`;

        -- Insert ignore so both calls don’t try to insert the same row
        INSERT IGNORE INTO `tbl_test` (`id`) VALUES (1);

        -- Sleep added to make it possible to run concurrently manually
        SELECT SLEEP(1) INTO @rubbish; 

        -- The result I am interested in
        SELECT COUNT(*) FROM `tbl_test`;

    COMMIT;

END $$

DELIMITER ;
复制步骤:

  • 在上面的脚本中运行以创建一个测试数据库、两个表和一个存储过程
  • 在两个独立的连接中,尽可能同时运行存储过程(如果需要更长的时间,可以增加
    睡眠时间):

  • 问题

    当在两个单独的连接上同时执行时,
    从'tbl_test'中选择COUNT(*)语句为两个调用返回不同的值

    当我执行上述步骤时,我从两个过程调用中的第一个过程调用返回
    1
    ,从第二个过程调用返回
    0

    我对事务行为和表锁定的理解是,当第一个调用到达
    INSERT
    语句时,它将创建一个锁。第二个过程调用将到达同一行,但必须等待第一个调用的事务提交。增加睡眠时间强化了这一想法,因为第二次通话需要两倍的时间才能完成。但是,如果是这种情况,那么第二个过程调用应该从第一个调用中提取insert,并且两个结果应该等于
    1

    TL;博士 我希望两者都等于
    1

    请注意,我使用
    READ_COMMITTED
    作为事务隔离级别

    我已经使用
    MYSQL服务器
    MariaDB

    进一步的怪异

    所以在这一点上,我认为我的理解是错误的。然而,我随后注意到,通过从'tbl_test2'中删除行
    SELECT*结果突然产生了预期值

    我一直在试验这个脚本,但本质上,在
    INSERT
    行导致意外结果之前,在数据库中的任何表中包含一个
    SELECT
    语句。我完全不知道为什么会这样

    问题

  • 我对预期交易行为的理解是否正确
  • 为什么对一个不相关的表执行
    SELECT
    语句会导致事务锁定失败
  • 如果有人能对此有所了解,我将不胜感激

    USE `testDB`;
    CALL sp_test ();