Это нормально для передачи ResultSet? - PullRequest
10 голосов
/ 05 ноября 2011

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

            //Build SQL String and Query Database.
        if(formValid){
            try {
                SQL = "SELECT * FROM users WHERE username=? AND email=?";
                Collections.addAll(fields, username, email);
                results = services.DataService.getData(SQL, fields);
                if (!results.next()){
                    errMessages.add("User account not found.");
                } else {
                    user = new User();
                    user.fillUser(results); //Is it ok to pass ResultSet Around?
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                services.DataService.closeDataObjects(); //Does this close the ResultSet I passed to fillUser?
            }
        }

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

    public void fillUser(ResultSet data) throws SQLException{
    setUserId(data.getInt("id"));
    setFirstName(data.getString("first_name"));
    setLastName(data.getString("last_name"));
    setUsername(data.getString("username"));
    setType(data.getString("type"));
    setEmail(data.getString("email"));
}

Я провел несколько тестов, и из того, что я могу определить, поскольку я закрываю исходный набор результатов в блоке finally запроса, набор результатов, который я передаю в метод fillUser, также закрывается. Или я не прав, и я серьезно утечки данных? Фактически это второй раз, когда я передаю набор результатов (так что его два экземпляра равны одному), потому что блок, который я использую для запроса к моей базе данных, -

    public static ResultSet getData(String SQL, ArrayList fields) throws SQLException {
    try{
        connection = Database.getConnection();
        preparedStatement = connection.prepareStatement(SQL);

        for(int i=0; i<fields.size(); i++){
            Integer num = i + 1;
            Object item = fields.get(i);

            if(item instanceof String){
                preparedStatement.setString(num, (String) item); //Array item is String.
            } else if (item instanceof Integer){
                preparedStatement.setInt(num, (Integer) item); //Array item is Integer.
            }
        }

        resultSet = preparedStatement.executeQuery();
        return resultSet;
    }finally{

    }
}

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

Ответы [ 2 ]

6 голосов
/ 05 ноября 2011

Технически, это нормально для передачи наборов результатов, если вы не сериализуете и не передаете его в другую JVM, а ваше соединение и оператор JDBC все еще открыты.

Однако это, вероятно, лучшее программное обеспечениеинженер и практика программирования, чтобы иметь уровень доступа к БД, который возвращает вам набор результатов в кодировке Java (список User в вашем примере).Таким образом, ваш код будет чище, и вам не придется беспокоиться, если ResultSet уже открыт или вам нужно прокрутить его до самого верха, назовите его ...

3 голосов
/ 21 июня 2014

Как все до меня говорили, плохая идея передать набор результатов. Если вы используете библиотеку пулов соединений, например c3p0 , вы можете безопасно использовать CachedRowSet и его реализацию CachedRowSetImpl . Используя это, вы можете закрыть соединение. Он будет использовать соединение только при необходимости. Вот фрагмент из документа Java:

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

Вот фрагмент кода для запроса и возврата ResultSet:

public ResultSet getContent(String queryStr) {
    Connection conn = null;
    Statement stmt = null;
    ResultSet resultSet = null;
    CachedRowSetImpl crs = null;
    try {
        Connection conn = dataSource.getConnection();
        stmt = conn.createStatement();
        resultSet = stmt.executeQuery(queryStr);

        crs = new CachedRowSetImpl();
        crs.populate(resultSet);
    } catch (SQLException e) {
        throw new IllegalStateException("Unable to execute query: " + queryStr, e);
    }finally {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (stmt != null) {
                stmt.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            LOGGER.error("Ignored", e);
        }
    }

    return crs;
}

Вот фрагмент кода для создания источника данных с использованием c3p0:

 ComboPooledDataSource cpds = new ComboPooledDataSource();
            try {
                cpds.setDriverClass("<driver class>"); //loads the jdbc driver
            } catch (PropertyVetoException e) {
                e.printStackTrace();
                return;
            }
            cpds.setJdbcUrl("jdbc:<url>");
            cpds.setMinPoolSize(5);
            cpds.setAcquireIncrement(5);
            cpds.setMaxPoolSize(20);

 javax.sql.DataSource dataSource = cpds;
...