我应该使用啥类型的数据结构来保存表行?

Posted

技术标签:

【中文标题】我应该使用啥类型的数据结构来保存表行?【英文标题】:What type of data structure should I use to hold table rows?我应该使用什么类型的数据结构来保存表行? 【发布时间】:2010-08-18 12:20:46 【问题描述】:

我是 Java 新手,刚刚开始查询数据库。到目前为止,我的结果在 ResultSetMetaData 中。我认为对于数据集中的每一行,我应该将其添加到某种形式的集合中?谁能告诉我这方面的最佳做法?

谢谢, 琼斯

【问题讨论】:

您的结果可能在 ResultSet 而不是 ResultSetMetaData 中。 【参考方案1】:

创建一个对象来保存数据。遍历结果集,为每个结果集创建一个对象,并将它们存储在 ArrayList 或 HashMap 中,具体取决于您希望如何使用数据。这允许您关闭数据库,并为您提供良好的对象,您可以在这些对象上构建操作数据的方法。

它还允许您编写使用不需要依赖数据库的对象的代码。如果您以后想拉出数据库并切换到文本文件或其他文件,这很容易做到,您仍然可以使用相同的对象和方法。

【讨论】:

感谢埃里克。我有一张用户表。我用构造函数创建了一个名为 DisplayUsers 的类来检索用户。例如,对于返回的每个用户,我应该创建一个 User 类的新对象吗? 是的,与数据库表中的字段具有相同属性的东西是有意义的。此外,通常,对象的名称与数据库表的名称非常相似。我使用一个单独的数据库类,它为我想要提取的数据类型实现源接口。但是我在很多不同的模块中大量使用数据库,并且我希望与源代码无关。【参考方案2】:

通常我们有一个类,其中的字段对应于一个表。然后,只要我们在结果集中有一个(完整的)行,我们就创建这个类的一个实例。

示例:

考虑这样创建的表:

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);

【讨论】:

在这种情况下,查询是否必须与对象创建代码在同一个类中? 不,但我会这样设计,除非应用程序大到可以分离查询和创建模型实例。该列表可以在其他地方创建,只需将其添加到那里以显示简短且非常完整的 sn-p。 好的,谢谢,如果您不介意,可以再问一个问题。一旦我创建了每条记录的对象。我可以用那个对象做什么样的事情?通常是.. 您可以在视图(表单、表格等)上显示数据或创建编辑器来修改现有的数据库表行(通过模型对象)或创建新的表条目。 感谢我发誓的最后一个问题!我遍历创建对象的每一行,然后将其添加到 ArrayList。然后我关闭数据库连接。我知道想通过 ArrayList 访问我的对象。我该怎么做呢?我似乎只能打印出对象的位置【参考方案3】:

List 似乎很合乎逻辑。如果您不打算重复,并且您不关心结果的顺序,那么也许是Set

List的相关实现:

ArrayList:这是由数组支持的,因此对特定索引的查找应该很快

Set的相关实现:

HashSet:由 HashMap 支持,所以 O(1) 插入时间 TreeSet:尊重数据的顺序(使用 compareTo 方法) - 因此迭代数据将是有序的 - 权衡是 O(log n) 插入时间

【讨论】:

【参考方案4】:

您可以创建代表现实世界实体的类。以后如果你想选择像hibernate这样的ORM技术/工具,你可以使用相同的类。

【讨论】:

【参考方案5】:

首先,ResultSetMetaData 类保存“有关 ResultSet 对象中列的类型和属性的信息”。所以查询的结果在 ResultSet 中,而不是在 ResultSetMetaData 对象中。

您可以查看Retrieving Values from Result Sets Java 教程,了解有关如何从 ResultSet 中提取数据的信息。您应该能够如图所示循环遍历 ResultSet 并将您的记录放在 List 或 Map 中,具体取决于您以后要如何访问数据。

【讨论】:

【参考方案6】:

我通常遵循 Andreas_D 所描述的模式。

用于包含每行数据的对象(在本例中为 Customer 类)称为数据传输对象 (TO)。

获取数据库连接、查询数据库、填充 TO 并返回它们(通常在列表中)的代码称为数据访问对象 (DAO)。

您可以阅读有关此设计模式的更多信息here

【讨论】:

【参考方案7】:

上面的许多答案都建议创建一个类来保存一行的列并创建类对象的数组列表。如果结果集很大,我们是否也应该担心,尽管只处理了更少的行,它不会过度消耗内存,除非垃圾收集器以与创建对象相同的速度回收。

【讨论】:

【参考方案8】:

我遇到了一个包含几十列的 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;

【讨论】:

以上是关于我应该使用啥类型的数据结构来保存表行?的主要内容,如果未能解决你的问题,请参考以下文章

Java 中应该使用啥数据类型来代表价格

金钱应该使用啥数据类型

iOS - 我应该使用啥来保存数据

Javascript - 选择啥文件类型来保存像素数据?

这是要保存在 mysql 1 - 4.9 上的啥数据类型

我应该使用啥样的意图来保存android设备生成的错误报告