#java #coding-style
#java — язык #стиль кодирования #java
Вопрос:
Я знаю, что жестко кодировать что-либо плохо. Обычно мы создаем большую часть переменной среды с помощью файла конфигурации. Например, свойство базы данных, конфигурация проекта, log4j, ввод, вывод.
Но сегодня я видел, как кто-то писал подобный код:
public void updateExistedRecord(SgsnMapping sgsnMapping) throws Exception {
PreparedStatement ps = null;
try {
String updateSql = "";
updateSql = "UPDATE " schema "." tableSgsnMapping " SET ";
//other where clause
ps = dbConn.prepareStatement(updateSql);
ps.executeUpdate();
} catch (Exception ex) {
logger.error("Error when update an existing record on " tableSgsnMapping " table.n" ex.getMessage(), ex);
throw ex;
} finally {
SqlHelper.close(ps);
}
}
Основное внимание уделяется таблице — tableSgsnMapping, она написана в другом месте таким образом:
private String tableSgsnMapping = ConstantManager.TABLE_SGSN_MAPPING;
В свою очередь, TABLE_SGSN_MAPPING определяется в другом месте:
public final static String TABLE_SGSN_MAPPING = "OBDUA_SGSN_MAPPING";
Не слишком ли это много? Таблица не изменит своего названия, и она всегда будет там. Почему бы просто не закодировать это жестко в программе? Почему?
Комментарии:
1. таблицы не изменили бы свое имя, но в коде могло бы быть несколько ссылок на имя таблицы, т. е. константа могла бы использоваться более чем в одном месте. И вам действительно не нужна частная строка tableSgsnMapping = ConstantManager. TABLE_SGSN_MAPPING и ConstantManager. TABLE_SGSN_MAPPING можно использовать сразу, и в дальнейшем, используя статический импорт, вы могли бы уменьшить его до TABLE_SGSN_MAPPING
2. Человек, лучше всего подходящий для ответа на вопрос «почему», — это тот, кто написал этот код. Почему бы тебе не спросить его? Вы оба знаете намного больше о конкретных обстоятельствах этого проекта, чем мы когда-либо узнаем.
Ответ №1:
Существует более серьезная проблема с использованием инструкций, созданных из строк (даже если они в константах) — вы можете открыть дверь для SQL-инъекции. С точки зрения безопасности, вместо этого лучше использовать подготовленные инструкции, задавая параметры с помощью setXXX()
методов, а не объединяя строки, как в вопросе.
И было бы неплохо иметь текст подготовленного оператора, определенный как постоянная строка в классе, где он используется, с заполнителями для параметров. Например:
private static final String query =
"update dbName.tableName set field = ? where condition = ?";
Комментарии:
1. Хорошие моменты.
PreparedStatements
более эффективно выполняются СУБД.2. В примере используются подготовленные утверждения. И SQL-инъекция обычно связана с неправильным пользовательским вводом, а не с саботажем со стороны команды разработчиков, не доверяющей константам из других классов. IMO это слишком параноидально для обычных вариантов использования
Ответ №2:
Значение tableSgsnMapping
всегда ConstantManager.TABLE_SGSN_MAPPING
равно? Тогда я бы использовал эту константу, возможно, как статический импорт, чтобы сэкономить немного места. Переназначение его локальной переменной может сбить с толку читателей и привести к ошибкам, если ее значение будет случайно изменено.
Ответ №3:
Имя таблицы может измениться не так, как вы говорите. Но кто знает будущее?
Но мой главный аргумент в пользу ConstantManager.TABLE_SGSN_MAPPING
заключается в том, что имена таблиц и столбцов обычно используются несколько раз в разных операторах и местах кода. Используя константы, вы можете быть уверены, что в одном редко используемом операторе SQL, касающемся этих вещей, нет опечаток. Мой любимый вопрос в этом углу: было ли имя таблицы во множественном числе или нет? («клиенты» против «customer»). Я просто не хочу думать об этом каждый раз снова — используя константы.