Как защитить агрегируемое поле таблицы базы данных от изменений из вне?

В базе данных 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?


Ответы (0 шт):