传递ResultSet是否可以?

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

//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{ } } 

所有这些代码片段都存在于不同的类中,并在整个项目中重复使用多次。 是否可以像这样传递结果集,或者我应该尝试另一种方法? 我的目标是减少代码冗余,但我不确定我是否以合法的方式处理它。

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

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

正如我之前的每个人都说过传递结果集一个坏主意。 如果您正在使用连接池库(如c3p0),那么您可以安全地使用CachedRowSet及其实现CachedRowSetImpl 。 使用此function,您可以关闭连接。 它只会在需要时使用连接。 这是来自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(""); //loads the jdbc driver } catch (PropertyVetoException e) { e.printStackTrace(); return; } cpds.setJdbcUrl("jdbc:"); cpds.setMinPoolSize(5); cpds.setAcquireIncrement(5); cpds.setMaxPoolSize(20); javax.sql.DataSource dataSource = cpds;