Доступ только из элементов Java в результирующем наборе


Этот код выглядит нормально?

public Map<String, String> getById(long id) {
    String sql = "select * from " + this._TABLE_NAME + " where id = ?";
    PreparedStatement p;
    Map<String, String> result = new HashMap<String, String>();
    try {
        p = conn.prepareStatement(sql);
        p.setLong(1, id);
        ResultSet rs = p.executeQuery();

        ResultSetMetaData rsmd = rs.getMetaData();
        int fieldsCount = rsmd.getColumnCount();
        // is this ok?
        rs.next();

        for (int i=1;i<fieldsCount+1;i++) {
            String cName = rsmd.getColumnName(i);
            result.put(cName, rs.getString(cName));
        }

    } catch (SQLException e) {
        e.printStackTrace();
    }

    return result;

}


2679
7
задан 13 апреля 2011 в 04:04 Источник Поделиться
Комментарии
5 ответов

Вот немного переделанная версия кода. Некоторые пояснения:


  • Предположим _TABLE_NAME является постоянным, поэтому нет необходимости строить запрос на каждый вызов метода.

  • Заставить соединение и закрыть ресурсы, чтобы избежать побочных эффектов.

  • Распространить ситуацию sqlexception для абонента (абонента должны решить, что делать с брошенным исключение).

Код:

private final static String GET_DATA_BY_ID = "select * from " + _TABLE_NAME + " where id = ?";

public Map<String, String> getById(long id) throws SQLException {

Connection conn = null;
Map<String, String> result = new HashMap<String, String>();

try {
conn = getConnection();

PreparedStatement preparedStatement = null;

ResultSet rs = null;
try {
preparedStatement = conn.prepareStatement(GET_DATA_BY_ID);
preparedStatement.setLong(1, id);
try {
rs = preparedStatement.executeQuery();

if (rs.next()) {
ResultSetMetaData rsmd = rs.getMetaData();
int fieldsCount = rsmd.getColumnCount();

for (int i = 1; i < fieldsCount + 1; i++) {
String cName = rsmd.getColumnName(i);
result.put(cName, rs.getString(cName));
}
}
} finally {
if (rs != null)
rs.close();
}
} finally {
if (preparedStatement != null)
preparedStatement.close();
}
} finally {
if (conn != null)
conn.close();
}
return result;
}

7
ответ дан 13 апреля 2011 в 06:04 Источник Поделиться

Вам не нужно проверить, если (РС != значение null) и если (объект PreparedStatement != значение null), потому что prepareStatement() и метод executequery() всегда возвращает значение null или нет. Просто объявить эти объекты без инициализации и закрыть их после. Же для связи, наверное.

5
ответ дан 13 апреля 2011 в 08:04 Источник Поделиться

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

Проверив в ResultSet и PreparedStatement, полученных с помощью JDBC реализации на null не нужна, так как если, например, получение результирующего набора по РС = объект PreparedStatement.метод executequery() не уже, это означает, что он не может быть закрыт в любом случае.

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

private final static String GET_DATA_BY_ID = 
"select * from " + _TABLE_NAME + " where id = ?";

public Map<String, String> getById(long id) throws YourSpecificPersistenceException {

final Map<String, String> result;
try {
Connection conn = getConnection();
try {

PreparedStatement preparedStatement =
conn.prepareStatement(GET_DATA_BY_ID);

try {
preparedStatement.setLong(1, id);
ResultSet rs = preparedStatement.executeQuery();

try {
if (rs.next()) {
ResultSetMetaData rsmd = rs.getMetaData();
int fieldsCount = rsmd.getColumnCount();
result = new HashMap<String, String>(fieldsCount);

for (int i = 1; i < fieldsCount + 1; i++) {
String cName = rsmd.getColumnName(i);
result.put(cName, rs.getString(cName));
}
} else {
result = Collections.emptyMap();
}
} finally {
rs.close();
}
} finally {
preparedStatement.close();
}
} finally {
conn.close();
}
} catch (SQLException e) {
throw new YourSpecificPersistenceException("Unable to execute statement: '"
+ GET_DATA_BY_ID + "' with parameter [" + id + "]", e);
}
return result;
}

5
ответ дан 13 апреля 2011 в 08:04 Источник Поделиться

Кроме того, то, что другие уже упоминалось, у меня есть пара вещей, чтобы сказать:


  • Именования переменных: р это слишком короткое имя переменной. Рассмотрим preStmt, полу или заявление вместо. (Я обычно использую полу сам) Кроме того, имя _TABLE_NAME не придерживается именование Java конвенций. Если это поле в классе, а затем использовать нижний регистр имен без подчеркивания в начале, как имя_таблицы.

  • Чтобы было более понятно, что вы делаете (что вы не перебираете в ResultSet, но только возвращается первая и единственная строка), позвоните РС.во-первых() вместо РС.далее().

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

  • Ваш объект PreparedStatement переменная должна быть объявлена внутри попробовать, так как он не нужен за его пределами. Это касается и вашего строку SQL - переменной.

Кроме этих вещей, я согласен с StitzL ответ

2
ответ дан 17 декабря 2013 в 05:12 Источник Поделиться

Почему бы просто не сделать это как:

while(rs.next()) {
result.put(....);
return result;
}

Вы также можете обернуть его в попробовать-поймать-наконец-то.

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

-2
ответ дан 13 апреля 2011 в 06:04 Источник Поделиться