Как защитить агрегируемое поле таблицы базы данных от изменений из вне?
В базе данных MySQL имеется таблица с постами posts
CREATE TABLE IF NOT EXISTS `posts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(128) NOT NULL,
`count_comments` int(11) NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB;
и таблица с комментариями comments
CREATE TABLE IF NOT EXISTS `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`post_id` int(11) NOT NULL,
`text` text NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB;
столбец posts.count_comments содержит количество комментариев для конкретного поста.
Проблема в том, что программный интерфейс позволяет записать в posts.count_comments любое значение. Что бы выйти из ситуации, нашла не очень красивый хак, состоящий из следующих процедур и триггеров.
DELIMITER |
-- добавляем комментарий (на обновление и удаление аналогичные)
CREATE TRIGGER AfterInsertComment
AFTER INSERT
ON comments
FOR EACH ROW
BEGIN
CALL ResetCommentCount(NEW.post_id);
END |
-- в процедуре указываем int`овому полу значение NULL, само поле NOT NULL,
-- это необходимо что бы распознать изменение как требуемое к перерасчёту
CREATE PROCEDURE ResetCommentCount(PostId INT)
BEGIN
UPDATE posts SET count_comments = NULL WHERE id = PostId;
END |
-- триггер на изменение таблицы posts
-- условие NEW.count_comments IS NULL проверяет необходимость в пересчёте, устанавливается в процедуре ResetCommentCount,
-- условие NEW.count_comments != OLD.count_comments обрабатывает попытку изменения извне
CREATE TRIGGER BeforeUpdatePost
BEFORE UPDATE
ON posts
FOR EACH ROW
BEGIN
IF NEW.count_comments IS NULL OR NEW.count_comments != OLD.count_comments THEN
NEW.count_comments = (
SELECT IFNULL(COUNT(*), 0)
FROM comments
WHERE s.post_id = NEW.id
);
END IF;
END |
Указывать в триггере BeforeUpdatePost условие, например, NEW.count_comments < 0 не получится, т.к. выше приведён частный случай использования. Так же не получится без NEW.count_comments IS NULL, потому что мы не узнаем что необходимо пересчитать количество комментариев.
Есть более удачный вариант, что бы не позволить изменить поле posts.count_comments ни чем кроме средств движка MySQL?