2016-12-20 2 views
3

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

online_order 
invoice 
customer_id 

Ваш босс звонит вам и говорит: «Мне нужно, чтобы заказать шоколадный торт для всех наших клиентов, выставлять счета им все отдельно ». Итак, теперь вы должны сделать две вещи:

  1. Создать online_order запись для каждого клиента
  2. Затем счет на их для этого заказа.

Однако каждый клиент должен иметь свой СОБСТВЕННЫЙ номер онлайн-заказа, который они могут ссылаться на свой счет.

Как вы можете это сделать за одну транзакцию? Ниже я имею (psuedocode), но я покажу вам свой результат и ожидаемый результат.

BEGIN; 
-- First lets create the order 
INSERT INTO online_order (online_order_id, date, cake_type, cake_flavor) 
VALUES 
(AUTO_INCREMENT, NOW(), round, chocolate); 

-- Then take that online_order_id and create an invoice out of it for one of our customers 
INSERT INTO invoice (date, online_order_id, invoice_amt, customer_id) 
SELECT 
    NOW(), 
    LAST_INSERT_ID(), 
    10.00, 
    CUSTOMER_ID 
FROM CUSTOMER; 

ROLLBACK; 
END; 

Мой выход

-- Let's say the next auto-incremented online_order_id is 10011: 
INSERT INTO invoice VALUES ("2016-01-01", 10011, 10.00, "1"); 
INSERT INTO invoice VALUES ("2016-01-01", 10011, 10.00, "2"); 
INSERT INTO invoice VALUES ("2016-01-01", 10011, 10.00, "3"); 
INSERT INTO invoice VALUES ("2016-01-01", 10011, 10.00, "4"); 
INSERT INTO invoice VALUES ("2016-01-01", 10011, 10.00, "5"); 

Желаемая выход (различные online_order_id для каждого счета-фактуры)

INSERT INTO invoice VALUES ("2016-01-01", 10011, 10.00, "1"); 
INSERT INTO invoice VALUES ("2016-01-01", 10012, 10.00, "2"); 
INSERT INTO invoice VALUES ("2016-01-01", 10013, 10.00, "3"); 
INSERT INTO invoice VALUES ("2016-01-01", 10014, 10.00, "4"); 
INSERT INTO invoice VALUES ("2016-01-01", 10015, 10.00, "5"); 

мне нужно вставить заказ, а затем вставьте счет, а затем вставить заказ, то вставьте счет-фактуру .... для каждого клиента. Как я могу написать это в MySQL? Спасибо!

+0

Вам нужна хранимая процедура, чтобы вы могли написать цикл. Или делайте это на языке приложений, таком как PHP или Python. – Barmar

+1

Откройте таблицу своих клиентов в курсоре в хранимой процедуре, прокрутите курсор и для каждого клиента сделайте 2 вставки и зафиксируйте в конце. – Shadow

+0

Ваш псевдокод вставляет только одну строку? И у вас нет клиента в ваших заказах? Это действительно то, что вы хотите? Если вы добавите клиента в таблицу заказов (и добавьте строку для каждого из них, используя «... от клиента»), вы можете просто использовать 'INSERT INTO invoice (...) выбрать« 2016-01-01 », online_order_id, 10.00, customer_id из online_order, где online_order_id> = last_insert_id() '. Любая реальная система erp будет использовать процедуру для создания счетов-фактур, но поскольку ваш вопрос кажется далеким от любых реальных проблем, вы можете сделать это именно так. – Solarflare

ответ

0

Вы можете создать таблицу для поддержания IDs для другого объекта и использовать SELECT.. FOR UPDATE для получения атомных значений. Таблица будет выглядеть следующим образом:

Entity | Value 
Order | 1 
Blah | 2 

Вы можете использовать следующий блок, чтобы получить новый идентификатор:

set @id := select value from Ids where Entity = 'Order' FOR UPDATE; 

update Ids set value = value + 1 Enity = 'Order'; 

commit; 

Это даст вам идентификатор и увеличиваем его на 1. Этот идентификатор затем может быть использован в invoide таблица.

Как вы будете использовать select.. for update, соответствующая строка будет заблокирована, и никакая другая транзакция не сможет прочитать/изменить значение, что приведет к атомичности.

Этот подход может оказаться узким местом, если у вас слишком много вставок, выполняемых параллельно.

0

Ваш псевдокод не имеет особого смысла - вы должны откатить транзакцию только в случае ее отказа. Но оставляя это на время, вставка одной строки за один раз очень неэффективна. Я бы с чем-то вроде ....

INSERT INTO invoice 
    (date, online_order_id, invoice_amt, customer_id, reference) 
SELECT 
    NOW(), LAST_INSERT_ID(), 10.00, CUSTOMER_ID, CONNECTION_ID() 
FROM CUSTOMER; 

INSERT INTO online_order 
(date, cake_type, cake_flavor) 
SELECT NOW(), 'round', 'chocolate' 
FROM invoice 
WHERE reference=CONNECTION_ID(); 

UPDATE invoice SET reference=NULL 
WHERE reference=CONNECTION_ID(); 

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

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