Должен ли я применять бизнес-логику через ошибки базы данных?
Есть интересное дизайнерское решение, о котором я думал в последнее время. Допустим, я добавляю имена пользователей в таблицу и хочу убедиться, что нет дубликатов. Столбец имени пользователя NOT NULL UNIQUE
, Я мог бы либо:
- Запросите базу данных перед вставкой, чтобы убедиться, что нет повторяющихся имен, или
- Просто
INSERT
и перехватывать любые исключения, поступающие из механизма базы данных.
Предполагая, что используемая БД способна налагать ограничения, мне было интересно, в каких ситуациях подходит каждый из этих вариантов.
3 ответа
Можете ли вы кешировать список имен пользователей и проверить его на стороне приложения, не заходя в базу данных? У вас все еще должно быть уникальное ограничение для базы данных, чтобы гарантировать, что никакие плохие данные не будут попадать (всегда защищайте данные на уровне базы данных в первую очередь), но если вы можете выполнить проверку из кэша, вы можете сохранить всю обратную передачу в база данных, когда кто-то выбирает то же имя пользователя, что и существующий пользователь. Теперь это может зависеть от размера данных, которые вам нужно будет кэшировать, и от того, как часто кэш должен обновляться. Не зная вашей системы, я не могу сказать, практична ли она, но я бы хотя бы занялся этим.
Почти всегда кажется хорошей идеей сделать вариант 2. Я бы не рекомендовал вариант 1, потому что вы фактически удвоили количество времени, необходимое для выполнения вставок (все они сначала требуют чтения). Кроме того, какой-то новый разработчик собирается просто фиксировать время, а не проверять, и он будет сломан.
Еще одна вещь, чтобы рассмотреть, сколько времени простоя подходит? Это критически важное приложение? Что произойдет, если бизнес-логика повреждена? Завершат ли заводы, если это так? Или это будут просто неприятные ошибки.
Вы не можете позволить себе закрыть свои фабрики, потому что некое исключение, о котором вы не думали, сломало ваш сервер. Так что, возможно, в этом случае может помочь еженедельная или еженедельная проверка правильности данных. Тем не менее, я считаю, что возможности БД для обеспечения уникальности (и, возможно, другие принудительные меры) являются подходящим способом.
Ожидаете ли вы, что новое имя пользователя, вероятно, будет уникальным? Или, скорее всего, это будет дубликат? Если имя пользователя, вероятно, будет уникальным, вставка и отлов исключения будут более эффективными. Если имя пользователя может быть дубликатом, будет более эффективно проверять наличие дубликатов (и, возможно, искать похожее, но еще не занятое имя пользователя), а не пытаться перехватить исключение. Очевидно, что разные базы данных и разные версии этих баз данных имеют разные точки безубыточности по относительной вероятности. Но в целом, если вы создаете систему для компании, в которой все равно имеют уникальное имя пользователя, вставьте и поймайте исключение. Если вы создаете Hotmail, сначала проверьте наличие дубликатов.
Быстрая демонстрация (в Oracle 11.2.0.1) показывает, что примерно в 7 раз дороже выполнить вставку, которая не удалась, и обработать исключение, чем выполнить проверку перед вставкой и затем записать данные.
SQL> create table username_test (
2 username varchar2(30) unique
3 );
Table created.
SQL> set timing on;
SQL> ed
Wrote file afiedt.buf
1 declare
2 l_cnt integer;
3 begin
4 for i in 1 .. 100000
5 loop
6 select count(*)
7 into l_cnt
8 from username_test
9 where username = 'JCAVE';
10 if( l_cnt = 0 )
11 then
12 insert into username_test( username )
13 values( 'JCAVE' );
14 end if;
15 end loop;
16* end;
SQL> /
PL/SQL procedure successfully completed.
Elapsed: 00:00:04.20
SQL> rollback;
Rollback complete.
Elapsed: 00:00:00.00
SQL> ed
Wrote file afiedt.buf
1 declare
2 l_cnt integer;
3 begin
4 for i in 1 .. 100000
5 loop
6 begin
7 insert into username_test( username )
8 values( 'JCAVE' );
9 exception
10 when dup_val_on_index then
11 null;
12 end;
13 end loop;
14* end;
SQL> /
PL/SQL procedure successfully completed.
Elapsed: 00:00:29.58