Блокировка и изоляция для шаблона резервирования ресурса - PullRequest
0 голосов
/ 22 октября 2018

Мне нужно решить шаблон резервирования ресурсов с помощью Spring и MariaDB.Проблема очень проста, у меня есть гостевая таблица, где я храню гостевые имена событий, я должен быть уверен, что число гостей для события должно быть меньше или равно максимальной емкости.

Это таблица:

create table guest(
    event int,
    name varchar(50)
)
create index event on guest (event);

Какова правильная процедура блокировки и уровень изоляции для БД?Обратите внимание, что этот код будет работать в многопоточном контейнере.Я решил заблокировать таблицу с помощью команды «SELECT ... FOR UPDATE», чтобы ограничить блокировку только одной строкой события.

// START TRANSACTION
@Transactional 
public void reserve(int event, String name){
    getJdbc().query("SELECT * FROM guest WHERE id=? FOR UPDATE",event);
    Integer count=getJdbc().queryForObject("SELECT COUNT(*) FROM guest WHERE id=?",Integer.class,event);
    if(count>=MAX_CAPACITY)
        throw new ApplicationException("No room left");
    getJdbc().query("INSERT INTO guest VALUES (?,?)",event,name);
}
// COMMIT

Я провел некоторый тест и, похоже, мне нужны уровни изоляции READ_COMMITTED,Я прав?Вот что я нашел: enter image description here

Это первый раз, когда мне нужно изменить уровень изоляции, и я немного удивлен этой необходимостью, можете ли вы подтвердить, что стандартОшибка уровня MariaDB REPETABLE_READ с этим шаблоном?

Ответы [ 2 ]

0 голосов
/ 26 октября 2018

Предложение для решения проблемы.Это включает в себя ведение счетчика вместо COUNT(*).(Да, это нарушает принцип отсутствия избыточной информации.)

CREATE TABLE EventCount ( event ..., ct INT ..., PRIMARY KEY(event) ) ENGINE=InnoDB;

START TRANSACTION;
    INSERT ...;
    UPDATE EventCount
        SET ct = ct + 1
        WHERE event = ?;
    ct = SELECT ct FROM EventCount WHERE event = ?;
    if (ct > max)
    {
        ROLLBACK;
        exit;
    }
COMMIT;

(Предостережение: я не проверял, что это работает для вашей ситуации.)

0 голосов
/ 26 октября 2018

Проблема в том, что во время транзакции в потоке 2 repeatable_read гарантирует, что вы увидите БД в том состоянии, в котором она была в начале транзакции.Таким образом, последствия транзакции 1, которая еще не была завершена, будут скрыты.Поэтому вы всегда будете видеть одинаковое количество записей независимо от того, что делали другие транзакции.Таким образом, обе транзакции будут вставлять запись.

READ_COMMITTED в соответствии с документацией означает: «Каждое согласованное чтение, даже в рамках одной и той же транзакции, устанавливает и считывает свой собственный свежий снимок».Свежий снимок означает, что результаты совершенных параллельных транзакций будут включены.

...