每个键值的循环自动增量

时间:2013-11-13 21:57:22

标签: php mysql transactions thread-safety

我有一些记录的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数据库中不是线程安全的)

你能帮忙吗?

由于

2 个答案:

答案 0 :(得分:3)

MyISAM支持此行为。创建一个双列主键,并使第二个列自动增加。它将从第一列中的每个不同值重新开始。

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必须搜索表中的其他行以查找每个相同j值的最大i值。如果其他人同时进行INSERT,则会产生竞争条件。

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

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

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


重新评论:

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

无论多列键中自动增量列的位置如何,只有在与InnoDB一起使用时才会增加;它不会为另一列中的每个不同值编号。

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

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

答案 1 :(得分:0)

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

LOCK TABLES `saved_fruit`;

-- Insert query with select.

UNLOCK TABLES;