Проверка данных должна происходить внутри базы данных или как можно ближе к ней, чтобы гарантировать, что данные действительны и остаются действительными.
Шаг нулевой: MySQL очень слабый. Много раз он будет принимать или усекать данные, которые другие базы данных отвергают. Переведите в более строгий режим, хотя бы traditional
режим .
Во-первых, используйте правильные типы столбцов. Вероятно, наиболее важным является использование типов даты и времени для даты и времени, а не для строк или чисел. Эти типы будут обеспечивать собственные проверки, обеспечивать их правильный формат и предлагать множество полезных функций .
Затем добавьте ограничения на то, какие данные разрешены в столбце. Самые основные c из них: not null
ограничения для обеспечения того, чтобы данные были заполнены чем-либо, unique
ограничения , чтобы гарантировать, что есть только одна вещь, и default
, чтобы обеспечить заполнение значения по умолчанию.
Для более общих проверок используйте ограничения проверки , которые MySQL наконец поддерживает начиная с 8.0.16. И, наконец, триггеры предлагают самые мощные ограничения.
Например, допустим, у вас есть таблица, заполненная пользовательскими данными. Ваш бизнес-логи c требует, чтобы ...
- У пользователя должно быть имя для входа.
- Имя входа должно быть уникальным.
- Пользователь имеет кредитов, которые начинаются с 0 и не могут быть меньше 0.
create table users (
id bigint primary key auto_increment,
login varchar(255) not null unique check(length(login) > 0),
credits integer not null default 0 check(credits >= 0)
);
Теперь невозможно иметь двух пользователей с одним и тем же логином, или пользователя без логина, или пустого логина, или отрицательный кредитный баланс.
mysql> insert into users (login) values ('');
ERROR 3819 (HY000): Check constraint 'users_chk_1' is violated.
Когда дело доходит до отношений, используйте ограничения внешнего ключа , чтобы гарантировать, что отношения не разорваны. Используйте ссылочные действия для очистки связанных данных.
Допустим, у вас есть вторая таблица для отслеживания логинов пользователей.
create table user_logins (
user_id bigint not null,
login_at datetime not null default current_timestamp,
foreign key(user_id) references users(id) on delete cascade
)
Теперь невозможно иметь запись user_logins без связанного пользователя. Также он не может иметь метку времени или отформатированную метку времени. А значение по умолчанию означает, что вам не нужно указывать временную метку, чтобы избежать еще одной возможной ошибки данных. Просто дайте ему действительный идентификатор пользователя.
insert into user_logins (user_id) values (5)
on delete cascade
гарантирует, что при удалении пользователя также удаляются связанные с ним user_logins.
-- All of user 5's user_logins are also deleted.
delete from users where id = 5
Demo
Наконец, используйте транзакции при изменении данных. Транзакция сохраняет свои изменения, только когда они все завершены.
Например, допустим, мы хотим переместить 100 кредитов от пользователя 5 пользователю 10.
begin
-- I've deliberately added credits first to demonstrate transactions.
update users
set credits = credits + 100
where id = 10;
update users
set credits = credits - 100
where id = 5;
end
Если пользователь 5 этого не делает. нет 100 кредитов, второе обновление не выполняется (из-за нашего ограничения проверки), транзакция откатывается, и ничего не меняется. Без транзакций пользователь 10 получает 100 бесплатных кредитов.