mysql 5.7 create TEMPORARY table

Рейтинг: 0Ответов: 1Опубликовано: 14.02.2023

Разрабатываю приложение в котором один из модулей должен выбрать свободные ресурсы из пула.

Для простоты будем считать что надо забронировать билеты в кинотеатре и надо избежать повторной продажи билетов.

Запросы при этом идут(или могут идти) параллельно

Вот работающий код, который решает эту задачу. Собственно использована инструкция select for update из документации.

Мне надо бронировать по 3 билета - поэтому понадобилась временная таблица. Поскольку запросы идут паралельно - то я не могу написать просто create TEMPORARY table T1 потому что T1 будет доступна и для второго запроса.

На выходе возвращаются забронированные места.

Поэтому пришлось городить на ровном месте такой не читаемый код.

Собственно ВОПРОС: можно ли что то придумать чтобы улучшить читаемость кода ? Например в MySQL 8 появились переменные типа table которые эту проблему решают

create table ticket_test
(
    seat  int primary key,
    count int default 0 null
);

Будем считать что count отображает занято место или нет (т.е. он должен быть только 0 или 1)

DELIMITER //

CREATE PROCEDURE testSelForUpdate2()
BEGIN

    SELECT CONCAT('gayrat_tmp_',REPLACE(TIME(NOW()),':','_')) INTO @tbl;

    SET @str=CONCAT("create TEMPORARY table ",@tbl," (seat int)");
    PREPARE stmt FROM @str;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
    START TRANSACTION;

    SET @str=CONCAT("INSERT INTO  ",@tbl," (SELECT seat FROM ticket_test where count=0 limit 3 for update)");
    PREPARE stmt FROM @str;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

    DO SLEEP(10);

    SET @str=CONCAT("update ticket_test inner join  ",@tbl,"  TT on ticket_test.seat = TT.seat set count=count+1;");
    PREPARE stmt FROM @str;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

    COMMIT;

    SET @str=CONCAT("select * from  ",@tbl);
    PREPARE stmt FROM @str;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

END //

DELIMITER ;

Ответы

▲ 0

Вместо temporary table надо применить обычную таблицу вида:

create table if not exists ggvlasey_avito.ticket_test_tmp
(
    jobId     varchar(50)                         null,
    seat      int                                 not null,
    timestamp timestamp default CURRENT_TIMESTAMP null
);

Для каждого запроса при бронировании места создаем случайную переменную

select HEX(RANDOM_BYTES(5)) as uuid4 into curUUID;

Так как сверху я написал Mysql 5.7 - то встроенная функциия UUID() работает на основе времени и чисто теоретически два запроса могут прийти в один и тот же момент времени - в этом случае UUID() будет иметь одинаковое значение - например если Вы запустите такой запрос - то значения будут совершенно одинаковыми select UUID(),UUID()

Запрос select HEX(RANDOM_BYTES(5)) ,HEX(RANDOM_BYTES(5)) выдаст разные значения

На SO попался код в котором предлагают применить функцию sha2() - но здесь она совершенно лишняя - так как просто вычисляет хеш - но не генерирует случайное число.

Обновленная версия процедуры выглядит так. DO SLEEP(10) исползуется для того чтобы я успел запустить запрос в другой консоли.

DELIMITER //
CREATE PROCEDURE testSelForUpdate3()
BEGIN
    DECLARE curUUID varchar(60);
    select HEX(RANDOM_BYTES(5)) as uuid4 into curUUID;
#     удалить старые записи из временной таблицы
    delete from ticket_test_tmp where timestamp < timestamp(DATE_SUB(NOW(), INTERVAL 5 MINUTE));


    START TRANSACTION;

    INSERT INTO ticket_test_tmp( jobId, seat)
        (SELECT curUUID, seat FROM ticket_test where count=0 limit 3 for update);

    DO SLEEP(10);

    update ticket_test
        inner join  ticket_test_tmp TT
            on ticket_test.seat = TT.seat and TT.jobId=curUUID
        set count=count+1;

    COMMIT;

    select seat from ticket_test_tmp where jobId=curUUID;

END //

DELIMITER ;