【发布时间】:2010-08-18 12:20:46
【问题描述】:
我是 Java 新手,刚刚开始查询数据库。到目前为止,我的结果在 ResultSetMetaData 中。我认为对于数据集中的每一行,我应该将其添加到某种形式的集合中?谁能告诉我这方面的最佳做法?
谢谢,
琼斯
【问题讨论】:
-
您的结果可能在 ResultSet 而不是 ResultSetMetaData 中。
标签: java sql jdbc collections
我是 Java 新手,刚刚开始查询数据库。到目前为止,我的结果在 ResultSetMetaData 中。我认为对于数据集中的每一行,我应该将其添加到某种形式的集合中?谁能告诉我这方面的最佳做法?
谢谢,
琼斯
【问题讨论】:
标签: java sql jdbc collections
创建一个对象来保存数据。遍历结果集,为每个结果集创建一个对象,并将它们存储在 ArrayList 或 HashMap 中,具体取决于您希望如何使用数据。这允许您关闭数据库,并为您提供良好的对象,您可以在这些对象上构建操作数据的方法。
它还允许您编写使用不需要依赖数据库的对象的代码。如果您以后想拉出数据库并切换到文本文件或其他文件,这很容易做到,您仍然可以使用相同的对象和方法。
【讨论】:
通常我们有一个类,其中的字段对应于一个表。然后,只要我们在结果集中有一个(完整的)行,我们就创建这个类的一个实例。
示例:
考虑这样创建的表:
CREATE TABLE customer (First_Name char(50), Last_Name char(50),
Address char(50), City char(50), Country char(25), Birth_Date date);
一个模型类应该是这样的:
public class Customer {
private String firstName;
private String lastName;
private String address;
private String city;
private String country;
private Date date;
public String getFirstName() {
return firstName;
}
// getters for all fields
public void setFirstName(String firstName) {
this.firstName = firstName;
}
// setters for all fields
public String toString() {
return String.format("[%s, %s, %s, %s, %s, %s]", firstName,
lastName, address, city, country, date);
}
}
现在,如果您读取数据并拥有一个 ResultSet,您将创建一个新的客户对象并设置字段:
List<Customer> customers = new ArrayList<Customer>();
ResultSet rs = stmt.executeQuery("SELECT * from CUSTOMER;");
while (rs.next()) {
Customer customer = new Customer();
customer.setFirstName(rs.get("First_Name"));
// ... and so on
customers.add(customer);
}
【讨论】:
List 似乎很合乎逻辑。如果您不打算重复,并且您不关心结果的顺序,那么也许是Set。
List的相关实现:
ArrayList:这是由数组支持的,因此对特定索引的查找应该很快Set的相关实现:
HashSet:由 HashMap 支持,所以 O(1) 插入时间TreeSet:尊重数据的顺序(使用 compareTo 方法) - 因此迭代数据将是有序的 - 权衡是 O(log n) 插入时间【讨论】:
您可以创建代表现实世界实体的类。以后如果你想选择像hibernate这样的ORM技术/工具,你可以使用相同的类。
【讨论】:
首先,ResultSetMetaData 类保存“有关 ResultSet 对象中列的类型和属性的信息”。所以查询的结果在 ResultSet 中,而不是在 ResultSetMetaData 对象中。
您可以查看Retrieving Values from Result Sets Java 教程,了解有关如何从 ResultSet 中提取数据的信息。您应该能够如图所示循环遍历 ResultSet 并将您的记录放在 List 或 Map 中,具体取决于您以后要如何访问数据。
【讨论】:
我通常遵循 Andreas_D 所描述的模式。
用于包含每行数据的对象(在本例中为 Customer 类)称为数据传输对象 (TO)。
获取数据库连接、查询数据库、填充 TO 并返回它们(通常在列表中)的代码称为数据访问对象 (DAO)。
您可以阅读有关此设计模式的更多信息here
【讨论】:
上面的许多答案都建议创建一个类来保存一行的列并创建类对象的数组列表。如果结果集很大,我们是否也应该担心,尽管只处理了更少的行,它不会过度消耗内存,除非垃圾收集器以与创建对象相同的速度回收。
【讨论】:
我遇到了一个包含几十列的 ResultSet 的问题,编写一个包含这么多成员的类对于懒惰的我来说工作量太大了。所以我将ResultSet的每个字段迭代成一个HashMap,列标签是键,字段是值。然后将每行中的所有哈希图放入一个单独的列表中,并将所有列表放入一个主列表中。
工作就像一个魅力。
private ArrayList<ArrayList<HashMap<String, Object>>> allRecords = new ArrayList<>();
public MyTable getRecords()throws IOException, SQLException{
try{
String query = new Utils().readResourceFile("MyQuery.sql");
ResultSet rs = DBUtils.dbConnect().createStatement().executeQuery(query);
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
while (rs.next()){
ArrayList<HashMap<String, Object>> row = new ArrayList<>();
for (int i = 1; i < columnCount + 1; i++) {
HashMap<String, Object> data = new HashMap<>();
Object field = rs.getObject(i);
data.put(rsmd.getColumnLabel(i), rs.wasNull()? "": field);
row.add(data);
}
allRecords.add(row);
}
}catch (IOException | ClassNotFoundException | SQLException e){
if(e instanceof SQLException){
DBUtils.printSQLException((SQLException) e);}
e.printStackTrace();
throw e;
}
return this;
}
这是我过滤数据的方式:
public MyTable makeChanges(){
for(int i = 0; i < allRecords.size(); i++){
Date startDate = (Date) allRecords.get(i).stream().filter((HashMap<String, Object> field) -> field.containsKey("StartDate")).findFirst().get().get("StartDate");
int product = (int) allRecords.get(i).stream().filter((HashMap<String, Object> field) -> field.containsKey("pk_Product")).findFirst().get().get("pk_Product");
// now do something....
}
return this;
}
【讨论】: