【问题标题】:cyclic autoincrement for each key value每个键值的循环自动增量
【发布时间】:2013-11-13 21:57:22
【问题描述】:

我有一些记录的mysql表,例如:

CREATE TABLE test (
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  value varchar NOT NULL
) 

现在,我需要的是在 php 脚本中生成 1、2、...、N 的唯一序列并存储到另一个表中... ?

我想知道一些额外的 mysql 表是否会有所帮助,但我不知道如何创建诸如“为每个列值单独自动增量”或其他任何东西......

test:
1 ... apples
2 ... oranges
3 ... lemons

一些 php 脚本(当时由多个用户并行访问):

save_next_fruit($_GET['fruit']); 

将在另一个表中创建一些记录,其值如下:

saved_fruit:
ID | FRUIT(FK) | FRUIT_NO
1      1            1
2      1            2      
3      2            1
4      3            1
5      3            2
6      1            3
7      3            3
8      2            2
9      1            4
10     2            3
11     1            5
12     2            4
13     1            6
14     3            4
15     3            5

换句话说,我需要这样做(例如水果 3(柠檬)):

insert into saved_fruit (fruit, fruit_no) values (3, select MAX(fruit_no)+1 from saved_fruit where fruit = 3);

但是以线程安全的方式(我知道上面的命令在 MyISAM MySQL 数据库中不是线程安全的)

你能帮忙吗?

谢谢

【问题讨论】:

  • 您想从test 表中获取插入的主键,还是想为另一个表创建一个新主键?
  • 我需要将test 表中的每个主键值单独序列到新表(而不是作为新表的键)
  • mysqli_insert_id()PDO::lastInsertId 也许?
  • 不,不是这样-我已经更新了原始问题-举个例子......我正在寻找线程安全的FRUIT_NO生成器(在mysql + php中)......跨度>
  • 我还没开始喝酒,我还是没有头绪。

标签: php mysql transactions thread-safety


【解决方案1】:

MyISAM 确实支持这种行为。创建一个双列主键,并使 second 列自动递增。它将针对第一列中的每个不同值重新开始。

CREATE TABLE t (i INT, j INT AUTO_INCREMENT, PRIMARY KEY (i,j)) ENGINE=MyISAM;
INSERT INTO t (i) VALUES (1), (1), (2), (2), (1), (3);
SELECT * FROM t; 

+---+---+
| i | j |
+---+---+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
| 3 | 1 |
+---+---+

但如果你仔细想想,这只是在为 INSERT 语句执行表级锁定的存储引擎中是线程安全的。因为 INSERT 必须搜索表中的其他行以找到每个相同 i 值的最大 j 值。如果其他人同时执行 INSERT,则会产生竞争条件。

因此,依赖于 MyISAM,它在 INSERT 上执行表级锁定。

请参阅手册中的此参考:http://dev.mysql.com/doc/refman/5.6/en/example-auto-increment.htmlMyISAM 注释部分下。

不使用 MyISAM 有很多充分的理由。对我来说,决定因素是 MyISAM 倾向于破坏数据。


你的评论:

InnoDB 不支持上述每组增量行为。您可以制作多列主键,但您得到的错误是因为 InnoDB 要求自增列是表的键中的第一列(它不一定是主键)

不管自增列在多列键中的位置如何,只有在与 InnoDB 一起使用时才会增加;它不会对另一列中每个不同值的条目进行编号。

要对 InnoDB 表执行此操作,您必须在 INSERT 期间显式锁定该表,以避免出现竞争条件。您将为要插入的组中的最大值执行自己的 SELECT 查询。然后插入该值 + 1。

基本上,您必须绕过自动增量功能并指定值,而不是让它们自动生成。

【讨论】:

  • 确实知道这种行为。你能指定文档的链接吗?
  • 好的,我添加了文档链接。
  • 好的,如果我想把它移到innoDB怎么办(我实际上可以,因为这个表是新的,不影响系统的旧部分)?该引擎的 DDL 命令(创建表)将不会成功,并出现错误“#1075 - 表定义不正确;只能有一个自动列,并且必须将其定义为键”...
【解决方案2】:

当您使用 MyISAM 时,您可以lock whole table

LOCK TABLES `saved_fruit`;

-- Insert query with select.

UNLOCK TABLES;

【讨论】:

  • 不,你不需要,你只需要让另一列成为主键的一部分。
  • 但是,如果另一列 不是 主键的一部分,那么您需要明确地进行表锁定是正确的。
猜你喜欢
  • 1970-01-01
  • 2017-10-27
  • 2011-11-24
  • 1970-01-01
  • 1970-01-01
  • 2020-02-10
  • 2014-05-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多