【问题标题】:Emulate auto-increment in MySQL/InnoDB在 MySQL/InnoDB 中模拟自动增量
【发布时间】:2011-03-18 13:23:33
【问题描述】:

假设我要在 MySQL/InnoDB 中模拟自动增量

条件

  1. 使用 MySQL/InnoDB
  2. ID字段没有唯一索引,也不是PK

是否可以仅使用程序逻辑进行模拟,而无需表级锁定。 谢谢。

【问题讨论】:

    标签: mysql innodb


    【解决方案1】:

    创建另一个表,其中包含存储下一个 id 值的单行和单列。然后在原始表上创建一个插入触发器,该触发器增加第二个表中的值,获取它,并将其用于第一个表上的 ID 列。您需要小心选择和更新的方式,以确保它们是原子的。

    本质上,您是在 MySQL 中模拟 Oracle sequence。但是,它会导致序列表中的单行锁定,因此可能不适合您正在执行的操作。

    预计到达时间:

    另一个类似但性能可能更好的选项是创建第二个“序列”表,该表只有一个自动增量 PK 列,没有其他数据。让您的插入触发器在该表中插入一行,并使用从那里生成的 ID 填充原始表中的 ID。然后让触发器或另一个进程定期从序列表中删除所有行以清理它。

    【讨论】:

      【解决方案2】:
      CREATE TABLE sequence (id INTEGER); -- possibbly add a name;
      INSERT INTO sequence VALUES (1); -- starting value
      
      SET AUTOCOMMIT=0;
      START TRANSACTION;
      UPDATE sequence SET id = LAST_INSERT_ID(id+1);
      INSERT INTO actualtable (non_autoincrementing_key) VALUES (LAST_INSERT_ID());
      COMMIT;
      

      SELECT LAST_INSERT_ID(); 甚至是一个会话安全值,用于检查您获得的 ID。确保您的表支持事务,或者序列中的漏洞没有问题。

      【讨论】:

        【解决方案3】:

        sequence table需要有id作为自增PK

        【讨论】:

          【解决方案4】:

          使用序列表和触发器 - 类似这样:

          drop table if exists users_seq;
          
          create table users_seq
          (
          next_seq_id int unsigned not null default 0
          )engine = innodb;
          
          drop table if exists users;
          
          create table users
          (
          user_id int unsigned not null primary key,
          username varchar(32) not null
          )engine = innodb;
          
          insert into users_seq values (0);
          
          delimiter #
          
          create trigger users_before_ins_trig before insert on users
          for each row
          begin
          
          declare id int unsigned default 0;
          
            select next_seq_id + 1 into id from users_seq;
          
            set new.user_id = id;
          
            update users_seq set next_seq_id = id;
          
          end#
          
          delimiter ;
          
          insert into users (username) values ('f00'),('bar'),('bish'),('bash'),('bosh');
          
          select * from users;
          select * from users_seq;
          
          insert into users (username) values ('newbie');
          
          select * from users;
          select * from users_seq;
          

          【讨论】:

            猜你喜欢
            • 2012-12-14
            • 1970-01-01
            • 1970-01-01
            • 2014-05-01
            • 2013-06-11
            • 2011-12-06
            • 2012-08-11
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多