Укажите конкретное и уникальное значение в столбце - PullRequest
0 голосов
/ 28 мая 2018

моя СУБД - это PostgreSQL.Я использую SpringBoot и Hibernate в качестве JPA.

Давайте рассмотрим очень простую таблицу с одним столбцом:

Man
    Age: integer

И я хотел бы реализовать такой метод, который добавляет человека в таблицу.Этот метод должен удовлетворять следующему условию:

At most one man in table can be 80 years old

.

@Transactional
void addMan(int age){
....
}

Похоже, мне нужна исключительная блокировка для всей таблицы, да?Как это сделать?

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

Я бы добавил уникальное ограничение / индекс к таблице и позволил бы работе базы данных.

create unique index man_age_unique_idx on man (age);

Если запись с таким возрастом еще не существует, нет проблем.

Если он существует, вы должны получить обратно PersistenceException, где причиной является Hibernate ConstraintViolationException.Из этого вы можете получить название ограничения, которое было нарушено, например, man_age_unique_idx в приведенном выше примере.

try {
    entityManager.persist(man);
} catch (PersistenceException e) {
    if (e.getCause() instanceof ConstraintViolationException) {
        ConstraintViolationException cve = (ConstraintViolationException) e.getCause();
        if (Objects.equals(cve.getConstraintName(), "man_age_unique_idx")) {
            // handle as appropriate... e.g. throw some custom business exception
            throw new DuplicateAgeException("Duplicate age: " + man.getAge(), e);
        }
    } else {
        // handle other causes ...
    }
}
0 голосов
/ 28 мая 2018

Существует второе решение.

Используйте SERIALIZABLE транзакции, которые выглядят следующим образом:

START TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SELECT count(*) FROM man WHERE age = 80;

Теперь, если результат равен 0, продолжайте:

INSERT INTO man VALUES (80);

COMMIT;

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...