传递ResultSet是否可以?

时间:2011-11-05 15:09:40

标签: java servlets jdbc

在我的情况下,我正在查询数据库以获取特定的回复(在这种情况下,基于用户名的注册信息)。

            //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 bean中的中心方法中。

    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 个答案:

答案 0 :(得分:6)

从技术上讲,传递结果集是可以的,只要您没有序列化并将其传递给不同的JVM,并且您的JDBC连接和语句仍处于打开状态。

然而,拥有数据库访问层可能是一个更好的软件工程师和编程实践,它以Java编码方式返回结果集(在您的示例中为User列表)。这样,你的代码会更清晰,你不必担心ResultSet是否已经打开,或者你必须将它滚动到顶部,你可以命名...

答案 1 :(得分:3)

正如我前面的每个人都说过传递结果集一个坏主意。如果您使用的是c3p0之类的连接池库,则可以安全地使用CachedRowSet及其实现CachedRowSetImpl。使用此功能,您可以关闭连接。它只会在需要时使用连接。这是来自java doc的片段:

  

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;