【问题标题】:Database inconsistent state MySQL/InnoDB数据库不一致状态 MySQL/InnoDB
【发布时间】:2015-04-04 10:18:35
【问题描述】:

我想知道是否有必要在最可能的并发环境中使用锁定以及如何在以下情况下。将MySQL database serverInnoDB 引擎一起使用

假设我有一张桌子

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,并发事务很可能发生。如果数据库可能处于不一致状态,我无法确定。同样使用FOR UPDATELOCK IN SHARE MODE 在这种情况下没有意义,因为事务处理新记录并且与特定行的更新无关。进一步LOCK TABLES在存储过程中是不允许的,是相当不够的。

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

【问题讨论】:

  • 手动 id 有另一个表 - 即只有一个自动增量字段的表,并从中获取您的 m_id

标签: mysql stored-procedures transactions innodb consistency


【解决方案1】:

事务处理新记录,与特定行的更新无关

这样的新记录被称为phantom

幻影

出现在查询结果集中但不在先前查询结果集中的行。例如,如果一个查询在一个事务中运行了两次,与此同时,另一个事务在插入新行或更新行以匹配@ 987654325@查询子句。

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

在不同的隔离级别中,serializable read级别可以防止幻读,而可重复读取一致读取和读取未提交级别强>。

所以为了防止幻象出现在任何语句上,可以简单地将事务隔离级别设置为SERIALIZABLE。 InnoDB 使用next-key locks 实现了这一点,它不仅锁定了您的查询匹配的记录,而且还锁定了这些记录之间的间隙

使用locking reads 可以在每个语句的基础上完成相同的操作,例如您在问题中描述的:LOCK IN SHARE MODEFOR UPDATE(前者允许并发会话在锁定时读取匹配记录到位,而后者没有)。

【讨论】:

    【解决方案2】:

    首先,一个序列表

      CREATE TABLE m_id_sequence (
          id integer primary key auto_increment
        );
    

    然后更改过程以从序列表中获取下一个 m_id

    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 ;
    

    【讨论】:

      猜你喜欢
      • 2018-10-25
      • 1970-01-01
      • 2010-09-12
      • 1970-01-01
      • 2014-01-12
      • 1970-01-01
      • 1970-01-01
      • 2011-04-23
      • 2015-05-24
      相关资源
      最近更新 更多