Как контролировать параллелизм в операторах INSERT с помощью Hibernate - PullRequest
0 голосов
/ 07 июня 2018

У меня проблема с контролем параллелизма при вставке данных через мое веб-приложение.

Контекст: у меня есть 3 таблицы (X, Y и Z), которые регистрируют госпитализации пациентов.Пациент не может иметь более одной активной госпитализации.

В настоящее время мое приложение выполняет проверку перед вставкой госпитализации INSERT в базу данных, которая проверяет, находится ли пациент уже в больнице.

Однако эта проверка действительноне работает, когда два или более пользователей пытаются принять одного и того же пациента в одно и то же время.

Что я делаю сейчас:

1 - verify if patient is already hospitalized (SELECT in table X)
  If not:
    begin transaction A;
      2 - INSERT in table X;
      3 - INSERT in table Y;
      4 - INSERT in table Z;
    end transaction A;

Как я упоминал ранее, проверка в 1 пытается избежатьпациентов от госпитализации дважды или более.Однако это не работает, если два (или более) пользователя пытаются одновременно принять одного и того же пациента.

Может быть, я могу использовать что-то, что может заблокировать выполнение инструкции SELECT до завершения транзакции A,Таким образом, SELECT идентифицирует, что пациент уже зарегистрирован при выполнении.

Я бы хотел решить эту проблему, используя EXPLICITING LOCKING из PostgreSQL в базе данных.В соответствии с документацией, я могу сделать что-то подобное, используя режим блокировки ACCESS EXCLUSIVE (поскольку это единственный режим, способный заблокировать оператор выбора).

Но как реализовать эту блокировку ACCESS EXCLUSIVE в Hibernate??

Я уже проверил и не могу обработать это, используя ограничения в базе данных

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

Чтобы убедиться, что не может быть двух госпитализаций для одного пациента, необходимо добавить уникальное ограничение в поле, которое является ссылкой от X (и / или Y, Z) к пациенту (я предполагаю, что уже естьполе типа patient_id, по крайней мере, в одной из этих таблиц, в противном случае как вы относитесь к пациенту, к которому относятся вставленные записи в X, Y и Z).

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

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

0 голосов
/ 07 июня 2018

Что вы пробовали?Ваш вопрос упоминает postgres.Я проверил их документацию здесь .Вы можете попробовать транзакцию на уровне Serializable Isolation Level , как определено в их спецификации, если вы хотите решить проблему с конца базы данных.

Из их документации грязное чтение, фантомное чтениеи неповторяемое чтение невозможно с этим уровнем изоляции.

В качестве альтернативы, если вы хотите решить проблему с Java, вы можете создать синхронизированную оболочку службы для любых классов, которые вам нужны, чтобы обеспечить соответствующую логику синхронизации.Так что если у вас есть

public interface MyService {
    public void hospitalize(Patient patient) throws Exception;
    // etc
}

с

public class MyServiceImpl implements MyService {
    @Transactional
    public void hospitalize(Patient patient) throws Exception {
        // your logic
    }
}

и

public MyServiceSerialImpl extends MyServiceImpl {
    @Override
    @Transactional
    public void hospitalize(Patient patient) throws Exception {
        // ...
        synchronized (lock) {
            super.hospitalize(patient);
        }

        // ...
    }

    private final Object lock = new Object();
}

или синхронизированы по всему методу, или что-то подобное.

EDIT

Как отметил Роман Коновал в комментариях, решение для синхронизации с Java не поможет, если имеется более одного приложения, кластера, более одного jvm,и т.д. База данных - это то место, где вам нужно работать.

...