Что лучше - выбрасывать исключение или проверять ошибки заранее - PullRequest
1 голос
/ 15 марта 2012

На моем сервере, который подключен к postgresql, я должен проверить, существует ли имя пользователя в таблице, выполнив "select * ...", а затем получить количество строк в наборе результатов, и i количество строк равно нулю, затем вставить имя пользователя?
Или просто введите имя пользователя в таблицу. Если он уже существует, он выдаст ошибку, которая затем может быть перехвачена.
Примечание: имя пользователя является первичным ключом

Делать какой из двух выше, лучше?

Ответы [ 9 ]

4 голосов
/ 15 марта 2012

Вы должны использовать метод «попробуй и поймай исключение» просто потому, что ты все равно должен это делать.

Если вы сначала проверите чек, ничто не помешает кому-то вставить строку для этого пользователя между вашим чеком и вашей вставкой, и в этом случае пользователь будет в таблице, даже если ваш чек не нашел ее.

За исключением возможности выполнить проверку и вставку в какой-либо транзакции (чтобы никто другой не мог вставить этого пользователя в промежуточный период). Вы не можете быть уверены, что без исключения сработает.

И хотя многие СУБД предоставляют поддержку транзакций, я не знаю любых , которые заблокируют строку, которую вам еще предстоит вставить: -)

Конечно, если ваше приложение разработано таким образом, что только ваш процесс будет вставлять пользователей (и сериализоваться), вы можете использовать метод check-first. Но я бы добавил обильные комментарии о том, что его нужно будет пересмотреть, если вы когда-нибудь увеличите его.

2 голосов
/ 15 марта 2012

Обычный консенсус заключается в использовании исключений только для исключительных случаев, а не в качестве конструкции потока управления.Попытка использовать имя пользователя, которое, как представляется, занято, должно, на мой взгляд, считаться допустимым, а не редким случаем использования.

Другими словами, я бы сначала проверил существующие имена пользователей.

Однако, как указывает @paxdiablo, если вы находитесь в многопоточной среде, такой как веб-сервер, то вам нужно либо добавить некоторую схему блокировки, либо использовать подход try / catch в любом случае (учитывая, что два потока могут конкурировать за добавление одного и того же имени пользователя)). Эта ситуация, тем не менее, может рассматриваться как исключительный случай.

Смежные вопросы (все с одним и тем же выводом, не используйте исключения для неисключительных случаев):

1 голос
/ 15 марта 2012

В этом случае ответ ни .Ни провоцируйте ошибку, ни проверяйте заранее.Ну, в любом случае в основном .
С ним можно работать проще - и безопаснее, и быстрее:

INSERT INTO users(username, col1)
SELECT 'max', 'val1'
WHERE  NOT EXISTS (SELECT * FROM users WHERE username = 'max')

Это добавит нового пользователя, только если он не существуетуже.PostgreSQL установит статус команды на 0 rows affected или 1 row affected, в зависимости от того, была ли она там уже.В любом случае, оно будет там после этого оператора.

Если вы хотите получить ответ:

INSERT INTO users(username, col1)
SELECT 'max', 'val1'
WHERE  NOT EXISTS (SELECT * FROM users WHERE username = 'max')
RETURNING username;

Это вернет имя пользователя, только если оно еще не существовало.
Однакооперация не является атомарной, поэтому, если у вас много параллелизма, установите блокировку таблицы следующим образом:

BEGIN;
LOCK TABLE users IN SHARE MODE;

INSERT INTO users(username, col1)
SELECT 'max', 'val1'
WHERE  NOT EXISTS (SELECT * FROM users WHERE username = 'max')
RETURNING username;

COMMIT;

Обратите внимание, что это все равно может завершиться ошибкой, даже если очень маловероятно - например, если другойтранзакция блокирует таблицу и блокирует вас навсегда из-за какой-то ошибки.
Итак, по общему признанию, вам все еще нужен код для обработки ошибки.Это никогда не должно происходить, если только у вашей базы данных или приложений нет проблем.

0 голосов
/ 15 марта 2012

Если вы вставите имя пользователя напрямую без какой-либо проверки и предположите, что такое же имя пользователя существует в базе данных, в это время вы получите исключение, в противном случае он успешно вставит запись в базу данных. В соответствии со стандартной практикой кодирования (на мой взгляд), вы должны сначала проверить уникальность и, если имя пользователя не существует в базе данных, затем вставить запись в базу данных.

0 голосов
/ 15 марта 2012

Вы получите множество ответов в духе «исключения не должны использоваться для управления потоком программы» и «исключения не для потока управления».На самом деле у вас уже есть несколько.Вы, как и я, можете найти эти утверждения совершенно бессмысленными.Исключения do управляют потоком программы, и когда API-интерфейс предназначен для создания исключения, у вас нет другого выбора, кроме как использовать его соответствующим образом.EOFException является показательным примером.При вызове методов, которые его генерируют, у вас нет другого способа обнаружить EOS.

В этом случае применяется другой принцип.Если вы тестируете, а затем устанавливаете, вы вводите временное окно, в течение которого последующий набор все равно может потерпеть неудачу, и если операция набора может вызвать исключение, вы все равно должны его кодировать.В этих ситуациях вы должны просто сделать набор и обработать исключение соответственно.Таким образом, ваша операция является атомарной, и вам не нужно писать один и тот же код дважды.В общем, самый надежный способ определить, доступен ли ресурс, - это попытаться использовать его (рассмотрите возможность подключения к сетевому серверу), а самый надежный способ определить, не удастся ли выполнить операцию, - это действительно попробовать его (рассмотрим этот случайт.е. вставка значения в структуру данных, в которой он является уникальным ключом).

Правило «исключения не должны использоваться для управления потоком программы» изначально исходило из гораздо более узкого контекста, означающего, что выв общем случае не следует выдавать исключения, которые вы перехватываете в рамках одного и того же метода, т.е. использовать их как своего рода GOTO.Однако, как это часто бывает в этой отрасли, первоначальная мотивация была полностью забыта в пользу того, что я могу описать только как бессмысленное повторение в стиле попугая.

0 голосов
/ 15 марта 2012

Я бы предпочел проверить, существует ли пользователь с помощью запроса, а не использовать исключение. Логика ошибки «пользователь существует» может вскоре стать бизнес-правилом. (ну, вы можете написать такие правила на SQL, но это совсем другой мир)

Или просто введите имя пользователя в таблицу. Если он уже существует, то он выдаст ошибку, которая затем может быть перехвачена

Проблема в том, что есть много других причин для исключения. Вы все равно должны справиться с ними.

0 голосов
/ 15 марта 2012

В вашем случае не нужно обрабатывать исключения, вам следует использовать первичный ключ с автоматическим приращением.

PostgreSQL Autoincrement

0 голосов
/ 15 марта 2012

исключения никогда не должны использоваться для управления потоком программы.Лучше избегать исключений, если это не исключение.

0 голосов
/ 15 марта 2012

Я бы сказал, что перехват исключения в таком случае является нарушением концепции исключения, если вы можете проверить это раньше, вы должны проверить это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...