简体   繁体   English

在Java中使用ResultSet

[英]Working with ResultSets in Java

I've ran into a problem of having to run a number of different queries on the DB (different return types, different number of columns, etc). 我遇到了一个问题,必须在数据库上运行许多不同的查询(不同的返回类型,不同的列数等)。 While writing that i started to wonder if there's a proper way of writing a helper function. 在编写时,我开始怀疑是否有编写辅助函数的正确方法。 It seemed that it's really easy to write a function that returns a ResultSet . 看起来写返回ResultSet的函数真的很容易。

However since it a) doesn't close connection b) doesn't close the result set it seems as a possibly working, but improper solution. 但是,由于a)不会关闭连接b)不会关闭结果集,因此这似乎是可行的,但解决方案不正确。 Is there any place to dump in all results so that they can be returned safely. 是否有任何地方可以存放所有结果,以便可以安全地退回它们。

(Only thing i could come up with, is just returning a 2D string array (after converting all data to strings) and then converting it all back) (我唯一能想到的就是返回一个二维字符串数组(将所有数据转换为字符串之后),然后再将其全部转换回去)

EDIT : Sorry for not writing clear, was wondering if there's any way to just store the result of the query as is (don't need to modify it) without writing a separate method for every possible return type. 编辑:对不起,我写得不清楚,想知道是否有任何方法可以按原样存储查询结果(不需要修改它),而不必为每种可能的返回类型编写单独的方法。

The idea behind a 2d string list is being able to store the query values as is. 2d字符串列表背后的想法是能够按原样存储查询值。

Col1 Row1 | Col2 Row1 | Col3 Row1
Col1 Row2 | Col2 Row2 | Col3 Row2

EDIT 2 Thank you for replies, i guess i'll just write a small parser for it. 编辑2感谢您的答复,我想我会为此写一个小型解析器。

You shouldn't be returning resultSets, you should read the results from the resultset into some kind of container object. 您不应该返回resultSet,应该将结果集中的结果读入某种容器对象。 A ResultSet is a wrapper around a database cursor, it goes away when the connection closes. ResultSet是数据库游标的包装,当连接关闭时它消失。 It's something you read from and close right away, not something you can pass around your application. 这是您读取并立即关闭的内容,而不是可以传递给应用程序的内容。

Look at how spring-jdbc does it. 看一下spring-jdbc是如何做到的。 You implement a resultSetMapper that is passed to the method on the JdbcTemplate. 您实现一个resultSetMapper,该结果传递给JdbcTemplate上的方法。

Several observations: 几点观察:

  • You don't need to use Spring to use spring-jdbc. 您无需使用Spring即可使用spring-jdbc。 However, I see very little value in reimplementing this stuff yourself. 但是,我认为自己重新实现此功能的价值很小。

  • It's not the job of the code that reads the ResultSet to open and close connections, that needs to be elsewhere. 读取ResultSet来打开和关闭连接不是代码的工作,它需要放在其他地方。

I'd recommend looking at Spring JDBC. 我建议看一下Spring JDBC。 Don't write such a thing yourself. 不要自己写这样的东西。 It's already been done, and quite well. 它已经完成,并且很好。

For example, I don't like your idea of returning a List of Strings . 例如,我不喜欢您返回Strings List的想法。 You lose a lot of info that way. 这样您会丢失很多信息。 I'd return a Map of Lists (column view) or List of Maps (row view). 我会返回MapLists (列视图)或ListMaps (行视图)。

If you must, here are some database utilities that would get you started. 如果必须的话,这里有一些数据库实用程序可以帮助您入门。

package persistence;

import java.sql.*;
import java.util.*;

/**
 * util.DatabaseUtils
 * User: Michael
 * Date: Aug 17, 2010
 * Time: 7:58:02 PM
 */
public class DatabaseUtils {
/*
    private static final String DEFAULT_DRIVER = "oracle.jdbc.driver.OracleDriver";
    private static final String DEFAULT_URL = "jdbc:oracle:thin:@host:1521:database";
    private static final String DEFAULT_USERNAME = "username";
    private static final String DEFAULT_PASSWORD = "password";
*/
/*
    private static final String DEFAULT_DRIVER = "org.postgresql.Driver";
    private static final String DEFAULT_URL = "jdbc:postgresql://localhost:5432/party";
    private static final String DEFAULT_USERNAME = "pgsuper";
    private static final String DEFAULT_PASSWORD = "pgsuper";
*/
    private static final String DEFAULT_DRIVER = "com.mysql.jdbc.Driver";
    private static final String DEFAULT_URL = "jdbc:mysql://localhost:3306/party";
    private static final String DEFAULT_USERNAME = "party";
    private static final String DEFAULT_PASSWORD = "party";

    public static void main(String[] args) {
        long begTime = System.currentTimeMillis();

        String driver = ((args.length > 0) ? args[0] : DEFAULT_DRIVER);
        String url = ((args.length > 1) ? args[1] : DEFAULT_URL);
        String username = ((args.length > 2) ? args[2] : DEFAULT_USERNAME);
        String password = ((args.length > 3) ? args[3] : DEFAULT_PASSWORD);

        Connection connection = null;

        try {
            connection = createConnection(driver, url, username, password);
            DatabaseMetaData meta = connection.getMetaData();
            System.out.println(meta.getDatabaseProductName());
            System.out.println(meta.getDatabaseProductVersion());

            String sqlQuery = "SELECT PERSON_ID, FIRST_NAME, LAST_NAME FROM PERSON ORDER BY LAST_NAME";
            System.out.println("before insert: " + query(connection, sqlQuery, Collections.EMPTY_LIST));

            connection.setAutoCommit(false);
            String sqlUpdate = "INSERT INTO PERSON(FIRST_NAME, LAST_NAME) VALUES(?,?)";
            List parameters = Arrays.asList("Foo", "Bar");
            int numRowsUpdated = update(connection, sqlUpdate, parameters);
            connection.commit();

            System.out.println("# rows inserted: " + numRowsUpdated);
            System.out.println("after insert: " + query(connection, sqlQuery, Collections.EMPTY_LIST));
        } catch (Exception e) {
            rollback(connection);
            e.printStackTrace();
        } finally {
            close(connection);
            long endTime = System.currentTimeMillis();
            System.out.println("wall time: " + (endTime - begTime) + " ms");
        }
    }

    public static Connection createConnection(String driver, String url, String username, String password) throws ClassNotFoundException, SQLException {
        Class.forName(driver);
        if ((username == null) || (password == null) || (username.trim().length() == 0) || (password.trim().length() == 0)) {
            return DriverManager.getConnection(url);
        } else {
            return DriverManager.getConnection(url, username, password);
        }
    }

    public static void close(Connection connection) {
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    public static void close(Statement st) {
        try {
            if (st != null) {
                st.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static void close(ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static void rollback(Connection connection) {
        try {
            if (connection != null) {
                connection.rollback();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static List<Map<String, Object>> map(ResultSet rs) throws SQLException {
        List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
        try {
            if (rs != null) {
                ResultSetMetaData meta = rs.getMetaData();
                int numColumns = meta.getColumnCount();
                while (rs.next()) {
                    Map<String, Object> row = new HashMap<String, Object>();
                    for (int i = 1; i <= numColumns; ++i) {
                        String name = meta.getColumnName(i);
                        Object value = rs.getObject(i);
                        row.put(name, value);
                    }
                    results.add(row);
                }
            }
        } finally {
            close(rs);
        }
        return results;
    }

    public static List<Map<String, Object>> query(Connection connection, String sql, List<Object> parameters) throws SQLException {
        List<Map<String, Object>> results = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = connection.prepareStatement(sql);

            int i = 0;
            for (Object parameter : parameters) {
                ps.setObject(++i, parameter);
            }
            rs = ps.executeQuery();
            results = map(rs);
        } finally {
            close(rs);
            close(ps);
        }
        return results;
    }

    public static int update(Connection connection, String sql, List<Object> parameters) throws SQLException {
        int numRowsUpdated = 0;
        PreparedStatement ps = null;
        try {
            ps = connection.prepareStatement(sql);

            int i = 0;
            for (Object parameter : parameters) {
                ps.setObject(++i, parameter);
            }
            numRowsUpdated = ps.executeUpdate();
        } finally {
            close(ps);
        }
        return numRowsUpdated;
    }
}

You can write helper functions that parse a ResultSet and convert it into an ArrayList or an array or even the fields of an object. 您可以编写用于解析ResultSet并将其转换为ArrayList或数组甚至对象字段的帮助函数。 For instance, lets say you have a table of orders and then a query returns all of the rows of that table for a particular user (customer). 例如,假设您有一个订单表,然后查询为特定用户(客户)返回该表的所有行。 We could then do something like this: 然后我们可以做这样的事情:

static List<Order> parseOrder(ResultSet rs) {
   ArrayList<Order> orderList = new ArrayList<>();
   while(rs.next() ) {
      Order order = new Order();
      order.setID(rs.getInt(1));
      order.setCustomerID(rs.getInt(2));
      order.setItemName(rs.getString(3));
      orderList.add(order);
  }
  return orderList;

} }

Simply turning the result set into an array of an array of Objects would be more general, but probably less useful. 简单地将结果集转换为Objects数组的数组会更通用,但可能用处不大。

I would leave it up to the calling function to close this ResultSet and possible the PreparedStatement (or Statement) and database connection. 我将留给调用函数以关闭此ResultSet以及可能的PreparedStatement(或Statement)和数据库连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM