Автор оригинала: Vlad Mihalcea.
Вступление
В этой статье мы собираемся протестировать реализацию пользовательских ограничений проверки SQL в MySQL 8. Хотя предложение CHECK является стандартной функцией SQL, до MySQL 8.0.16 это предложение анализировалось и игнорировалось, поэтому эту функциональность можно было эмулировать только с помощью триггеров ВСТАВКИ и ОБНОВЛЕНИЯ.
Как протестировать реализацию пользовательских ограничений проверки SQL в MySQL 8 @vlad_mihalcea https://t.co/4rDn4J6K5p pic.twitter.com/kPWL6aFIZ2
Пользовательские ограничения ПРОВЕРКИ SQL
Как я объяснил в этой статье , пользовательские ограничения ПРОВЕРКИ SQL очень полезны для обеспечения ограничений, не допускающих обнуления, для атрибутов подкласса сущности JPA при использовании стратегии наследования JPA для ОДНОЙ ТАБЛИЦЫ.
Чтобы понять проблему, рассмотрим, что у нас есть следующая модель предметной области:
При использовании стратегии наследования ОДНОЙ ТАБЛИЦЫ базовый класс и все подклассы используют одну и ту же таблицу базы данных:
Однако, если атрибуты, относящиеся к подклассу, такие как content и validUntil атрибуты Post и Объявление сущностей, должны быть ненулевыми, мы не можем просто добавить ограничение NOT NULL на уровне столбца SQL, так как в противном случае мы не сможем добавить запись post как valid_until столбец NOT NULL ограничение не будет выполнено.
Именно в этом нам могут помочь ограничения пользовательских проверок SQL. Поэтому мы могли бы добавить следующие два КОНТРОЛЬНЫХ ограничения:
ALTER TABLE topic
ADD CONSTRAINT post_content_check
CHECK (
CASE
WHEN DTYPE = 'Post'
THEN
CASE
WHEN content IS NOT NULL
THEN 1
ELSE 0
END
ELSE 1
END = 1
)
ALTER TABLE topic
ADD CONSTRAINT announcement_validUntil_check
CHECK (
CASE
WHEN DTYPE = 'Announcement'
THEN
CASE
WHEN validUntil IS NOT NULL
THEN 1
ELSE 0
END
ELSE 1
END = 1
)
MySQL 8 поддерживает пользовательские ограничения проверки SQL
Теперь, если мы попытаемся сохранить Сообщение сущность без действительного содержимого свойства:
entityManager.persist(new Post());
MySQL 8.0.16 собирается выдать следующее Исключение ConstraintViolationException :
INSERT INTO topic (
board_id,
createdOn,
owner,
title,
content,
DTYPE,
id
)
VALUES (
NULL(BIGINT),
'2019-07-03 10:40:03.933',
NULL(VARCHAR),
NULL(VARCHAR),
NULL(VARCHAR),
'Post',
4
)
-- SQL Error: 1644, SQLState: 45000
-- Post content cannot be NULL
То же самое произойдет, если мы попытаемся обновить существующую сущность Post и установим атрибут content равным null :
Post post = entityManager
.createQuery(
"select p " +
"from Post p " +
"where p.content = :content", Post.class)
.setParameter("content", "Best practices")
.getSingleResult();
post.setContent(null);
MySQL 8.0.16 собирается создать исключение ConstraintViolationException , потому что пользовательское ограничение post_content_check CHECK не проверяет инструкцию UPDATE:
UPDATE topic
SET
board_id = 1,
createdOn = '2019-07-03 10:45:53.581',
owner = 'John Doe',
title = 'Inheritance',
content = NULL(VARCHAR)
WHERE
id = 2
-- SQL Error: 1644, SQLState: 45000
-- Post content cannot be NULL
Потрясающе, правда?
Если вы хотите узнать, что вам нужно было сделать, чтобы эмулировать ограничение CHECK для MySQL до 8.0.16. затем ознакомьтесь с этой статьей .
Вывод
Если вы все еще используете более старую версию MySQL, вам определенно следует рассмотреть возможность обновления до версии 8.0 , поскольку в MySQL было добавлено много функций в этом основном приращении версии (например , функции окон, ПРОПУСК ЗАБЛОКИРОВАН и NOWAIT, CTE или Рекурсивный CTE ).