2013-11-13 4 views
1

У меня есть MySQL таблицы некоторых записей, например:циклическая автоинкремент для каждого значения ключа

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

сейчас, что мне нужно, чтобы сгенерировать уникальную последовательность 1, 2, ..., N в PHP скрипт и хранить в другой таблице ... Как достичь этого, чтобы быть потокобезопасным, а не создавать парные или что-то пропускать?

мне было интересно, если какая-то дополнительная таблица MySQL может быть полезной, но я не знаю, как создать что-то вроде «отдельных autoincrements для каждого значения столбца» или что-нибудь еще ...

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)

Можете ли вы помочь?

Thanks

+0

Вы хотите получить вставленный первичный ключ из таблицы 'test' или хотите новый для другой таблицы? – AbraCadaver

+0

Мне нужна отдельная последовательность для каждого значения первичного ключа в таблице 'test' для новой таблицы (а не как ключ новой таблицы) – tomas

+0

' mysqli_insert_id() 'или' PDO :: lastInsertId' может быть? – AbraCadaver

ответ

2

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 должен искать другие строки в таблице, чтобы найти значение max j за одно и то же значение i. Если другие люди делают INSERT одновременно, это создает условие гонки.

Таким образом, зависимость от MyISAM, которая блокирует на уровне таблицы INSERT.

См. Эту ссылку в руководстве: http://dev.mysql.com/doc/refman/5.6/en/example-auto-increment.html по разделу MyISAM Примечания.

Есть много веских причин не использовать MyISAM. Решающим фактором для меня является тенденция MyISAM к искажению данных.


Re вашего комментарий:

InnoDB не поддерживает поведение инкремента-в-группы, описанное выше. Вы можете сделать первичный ключ с несколькими столбцами, но полученная вами ошибка связана с тем, что InnoDB требует, чтобы столбец с автоматическим приращением был первым столбцом в ключе таблицы (он не обязательно должен быть первичным ключом)

Независимо от положения столбца автоинкремент в многоколоночном ключе он увеличивается только при использовании его с InnoDB; он не числивает записи на отдельное значение в другом столбце.

Чтобы сделать это с помощью таблицы InnoDB, вам нужно будет заблокировать таблицу в явном виде на время INSERT, чтобы избежать условий гонки. Вы сделаете свой собственный запрос SELECT для максимального значения в группе, в которую вы вставляете. Затем вставьте это значение + 1.

В принципе, вам необходимо обойти функцию автоматического увеличения и указать значения вместо их автоматического создания.

+0

Знал это поведение. Не могли бы вы указать ссылку на документацию? – sectus

+0

Хорошо, я добавил ссылка на документацию –

+0

ОК, что, если я хочу перенести ее в innoDB (на самом деле я могу, потому что эта таблица новая, не затрагивая старые части системы)? Команда DDL (создать таблицу) не будет успешной для этого двигатель с ошибкой "# 1075 - Неверное определение таблицы, может быть только один автоматический столбец, и он должен быть определен как ключ" ... – tomas

0

Как вы используете MyISAM, вы можете до lock whole table.

LOCK TABLES `saved_fruit`; 

-- Insert query with select. 

UNLOCK TABLES; 
+0

Нет, вы этого не сделаете, вам просто нужно сделать другой столбец частью основного ключ –

+0

@BillKarwin, вы правы. – sectus

+0

Но, если другой столбец * не является * частью первичного ключа, то вы правы, что вам нужно явно блокировать таблицу. –

Смежные вопросы