数据库状态不一致MySQL/InnoDB

数据库状态不一致MySQL/InnoDB,mysql,stored-procedures,transactions,innodb,consistency,Mysql,Stored Procedures,Transactions,Innodb,Consistency,我想知道是否有必要在最有可能的并发环境中使用锁定,以及在以下情况下如何。使用MySQL数据库服务器和InnoDB引擎 假设我有一张桌子 CREATE TABLE `A` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, `m_id` INT NOT NULL, -- manual id `name` VARCHAR(10) ) ENGINE=INNODB; 程序呢? CREATE PROCEDURE `add_r

我想知道是否有必要在最有可能的并发环境中使用锁定,以及在以下情况下如何。使用
MySQL数据库服务器
InnoDB
引擎

假设我有一张桌子

CREATE TABLE `A` (
    `id`    INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `m_id`  INT NOT NULL, -- manual id
    `name`  VARCHAR(10)
)  ENGINE=INNODB;
程序呢?

CREATE PROCEDURE `add_record`(IN _NAME VARCHAR(10))
BEGIN
    DECLARE _m_id INT;
    DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
    START TRANSACTION;

    SELECT (`m_id` + 1) INTO _m_id FROM `A` WHERE `id` = (SELECT MAX(`id`) FROM `A`);

    INSERT INTO `A`(`m_id`, `name`) VALUES(_m_id, _NAME);

    COMMIT;
END$$
正如您所看到的,事实是我正在手动增加
m_id
,并发事务最有可能发生。我无法确定数据库是否会处于不一致的状态。在这种情况下,使用
进行更新
在共享模式下锁定
也没有意义,因为事务处理的是新记录,与特定行上的更新无关。存储过程中不允许使用进一步的
锁表
,这是非常不够的


所以,我的问题是,如果实际情况可能发生,如何避免标记场景中的不一致状态。任何建议都将不胜感激

首先是序列表

  CREATE TABLE m_id_sequence (
      id integer primary key auto_increment
    );
DELIMITER $$
CREATE PROCEDURE `add_record`(IN _NAME VARCHAR(10))
BEGIN
    DECLARE _m_id INT;
    DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
    START TRANSACTION;

    INSERT INTO m_id_sequence VALUES ();
    SET _m_id = LAST_INSERT_ID();

    INSERT INTO `A`(`m_id`, `name`) VALUES(_m_id, _NAME);

    COMMIT;
END$$
DELIMITER ;
然后修改程序,从序列表中获取下一个m_id

  CREATE TABLE m_id_sequence (
      id integer primary key auto_increment
    );
DELIMITER $$
CREATE PROCEDURE `add_record`(IN _NAME VARCHAR(10))
BEGIN
    DECLARE _m_id INT;
    DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
    START TRANSACTION;

    INSERT INTO m_id_sequence VALUES ();
    SET _m_id = LAST_INSERT_ID();

    INSERT INTO `A`(`m_id`, `name`) VALUES(_m_id, _NAME);

    COMMIT;
END$$
DELIMITER ;
事务处理新记录,与特定行上的更新无关

这种新记录称为:

幻影 显示在查询结果集中,但不显示在早期查询结果集中的行。例如,如果一个查询在一个事务中运行了两次,同时,另一个事务在插入新行或更新行以使其与查询的
WHERE
子句匹配后提交

这种情况称为幻象读取。这比不可重复读取更难防范,因为锁定第一个查询结果集中的所有行不会阻止导致幻影出现的更改

在不同的隔离级别中,幻像读取由可序列化读取级别阻止,并由可重复读取一致读取和读取未提交级别允许

因此,为了防止任何语句出现幻影,只需将事务隔离级别设置为。InnoDB使用实现此功能,它不仅锁定查询匹配的记录,而且还锁定这些记录之间的间隔


通过使用,例如您在问题中描述的:
在共享模式下锁定
用于更新
(前者允许并发会话在锁定到位时读取匹配的记录,而后者则不允许).

为手动id创建另一个表-即仅包含自动递增字段的表,并从中获取m_id