如何将 ResultSet 放入 ArrayList?

9
“ResultSet”被认为是ArrayList吗?我在谈论jdbc。如果不是,那么我如何使用“ResultSet”从我的数据库中获取信息?
while (result.next()) {
....

}

将语法转换成类似hotelResult的ArrayList中,我希望这句话可以被理解。

1
你做最艰难的部分:手工搭建它。 - kolossus
2
只需在您的ResultSet上进行迭代,并将所有元素添加到ArrayList中即可。 - AndreDuarte
1
嗯...我不确定该怎么做。我是Java的新手。假设我想将hotelNo添加到我的ArrayList中...我应该使用什么语法?我真的不知道 :/谢谢您的快速回答! :) - Adem Ökmen
2
文档可能会有所帮助。列出的唯一超级接口是AutocloseableWrapper,而ArrayList具有完全不同的接口列表。(查看ArrayList.add)换句话说,ResultSet不是一个数组列表。这里有一个合理的例子 - Patrick M
如果您想要添加到您的ArrayList中,语法是:hotelResult.add()。 - Gary
7个回答

16

ResultSet不是ArrayList。它是一个特殊的对象(接口),用于通过JDBC连接检索查询结果。

ResultSet对象无法更新,只能向前遍历,不能向后。默认情况下,您只能一次迭代它,从第一行到最后一行(尽管通过一些编码,您可以生成一个可编辑和双向遍历的ResultSet对象)。

存储在ResultSet对象中的记录可以轻松放入ArrayList中。以下是如何执行此操作的示例:

Connection con = ... ;
Statement stmt = ... ;
ResultSet results = stmt.executeQuery("..."); 

//Stores properties of a ResultSet object, including column count
ResultSetMetaData rsmd = results.getMetaData(); 
int columnCount = rsmd.getColumnCount();

ArrayList<String> hotelResultList = new ArrayList<>(columnCount); 
while (results.next()) {              
   int i = 1;
   while(i <= columnCount) {
        hotelResultList.add(results.getString(i++));
   }
}

注意:此示例假定查询返回单个字符串,例如酒店名称。 您可能希望保存有关每个酒店的多个数据,这种情况下您将创建一个“Hotel”对象,然后将ArrayList创建为Hotel对象列表。通过使用行映射器,每个酒店对象可以填充相关数据。

此外,使用流行的JDBC框架来处理JDBC连接、查询和结果集可以进一步简化该过程。


谢谢,这正是我所需要的。 - Chef1075

8

我会帮你解决问题。在类中创建所需的变量,可以参考我的示例 :)

public class HotelData {
    private String hotelName = null;
    private int hotelTelephone = 0;

    public HotelData(String hotelName, int hotelTelephone) {
    this.hotelName = hotelName;
    this.hotelTelephone = hotelTelephone;
    }
}

现在创建 ArrayList:
public ArrayList<HotelData> hotelResult = new ArrayList<HotelData>();

现在使用while方法:

while(result.next()) {
    hotelResult.add(new HotelData(result.getString("Enter columnname"), result.getInt("Enter colummname")));
}

希望这能对你有所帮助,伙计 :)!如果你需要从ArrayList中获取数据,你可以在HotelData类中编写自己的get方法!


啊,太好了。非常感谢!只有一个问题:我没有使用hotelData类就使其工作了?我们为什么需要它?我做了这个:<code>ArrayList<String> hotelInfo = new ArrayList<String>(); while(result.next()) { hotelInfo.add(result.getString("hotelNo")); // how come it works when it's an INT not a STRING?? hotelInfo.add(result.getString("hotelName")); hotelInfo.add(result.getString("city")); System.out.println(hotelInfo); }</code>再次编辑:对不起。我不知道如何格式化代码,以便在这里显示得好看。 - Adem Ökmen
看看我在这个话题中的新帖子吧 ;) - Bart1612

5
不,ResultSet不是被认为是ArrayList而是一个表格。例如,如果hotelResult的类型是String,你可以用下面这段代码将列表填充(如果ResultSet的列是String)。
while(result.next()) {
  hotelResult.add(result.getString("Enter the columnname here");
}

每种数据类型都有一种从ResultSet中获取值的方法。在Java API中查找不同种类的方法。


好的,我想我明白了。嗯...现在我又遇到了另一个问题。我的老师让我把一些数据库中的信息放入ArrayList中。如果只有字符串,我现在认为我知道如何做了,但是在我的情况下,我有String、Int和(var)Char。我该如何将这些信息放入单个ArrayList中呢? - Adem Ökmen
@AdemÖkmen 创建一个带有信息属性的对象,创建一个“ResultSet”中一行的对象,并将其添加到列表中。 - Mark Rotteveel
是的,就像Mark Rotteveel所说的那样。创建一个名为HotelData的类,在HotelData类中创建String和int变量。据我所知,varchar与String相同 :)! - Bart1612
@AdemÖkmen 请看我在Michael M的帖子下面发的帖子。 - Bart1612

1
我相信这会清楚- ArrayList hotels 保存了 HotelDtos 对象。
public class HotelDto {
private String hotelName;
private String hotelAddress;

private int hotelRank;

public String getHotelName() {
    return hotelName;
}

public void setHotelName(String hotelName) {
    this.hotelName = hotelName;
}

public String getHotelAddress() {
    return hotelAddress;
}

public void setHotelAddress(String hotelAddress) {
    this.hotelAddress = hotelAddress;
}

public int getHotelRank() {
    return hotelRank;
}

public void setHotelRank(int hotelRank) {
    this.hotelRank = hotelRank;
}

}

public class HotelDao {

public List<HotelDto> getHotlInfo(String hotelName) {

    List<HotelDto> hotels = new ArrayList<HotelDto>();
    try {

        String query = "SELECT  hotelName, hotelAddress,hotelrank " + "FROM   HOTELS_TABLE "
                + "WHERE hotelName = " + "'" + hotelName + "'" + " ";

        ResultSet resultSet = DBConnection.getDBConnection().createStatement().executeQuery(query);

        int i = 0;

        while (resultSet.next()) {

            HotelDto hDto = new HotelDto();
            hDto.setHotelName(resultSet.getString(1));
            hDto.setHotelAddress(resultSet.getString(2));
            hDto.setHotelrank(resultSet.getInt(3));
            hotels.add(i, hDto);
            i++;
        }

    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        return hotels;
    }

}

}


0
如果您想知道如何获取添加到列表中的数据库值,以下是解决方案。
  1. pom.xml 文件中添加以下依赖项:

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>18.0</version>
    </dependency>
    
  2. 从主程序中调用该方法:

    List output =  readRows(rs);
    

    这里的 rsResultSet 对象,readRows() 是方法名。

  3. 以下是 readRows() 方法的代码片段:

    private static List<List<Object>> readRows(ResultSet rs) throws SQLException
    {
        ImmutableList.Builder<List<Object>> rows = ImmutableList.builder();
        int columnCount = rs.getMetaData().getColumnCount();
        while (rs.next()) {
            List<Object> row = new ArrayList<>();
            for (int i = 1; i <= columnCount; i++) {
                row.add(rs.getObject(i));
            }
            rows.add(row);
        }
        return rows.build();
    }
    

0
回答你的第一个问题,你其实不需要HotelData类。 这个类唯一要做的就是将数据整齐地保存在一个对象中(对于每个特定的酒店)。
如果按照你的方式实现,你必须先将所有的值转换为字符串(如果它们不包含字符串值),然后才能将项目存储在hotelInfo列表中。这是因为hotelInfo列表具有字符串类型,在我的实现中也不需要(强制转换),因为我已经创建了一个构造函数,其中一个是字符串值,另一个是整数值。
如果你想让你的示例起作用,请按照以下方式实现:
不是这样写:hotelInfo.add(result.getString("hotelNo"));
而是这样写:hotelInfo.add("" + result.getInt("hotelNo")); //注意这里的转换!

谢谢你们的回复,这对我来说真的很重要 :)好的,我尝试了你们的方法,包括强制类型转换,但是它显示“无法从int转换为String”。然而,如果按照我的方式操作,我实际上可以将所有内容正确地打印到控制台中。它甚至包括整数。 所以我认为它正在工作(至少现在是这样,在这个项目中还需要大量的工作)。我不会再打扰你们了。感谢你们的帮助。时间已经很晚了,我需要睡觉了。也许明天会有新问题,呵呵。 - Adem Ökmen
Adem,我为你找到了解决方法,我犯了个错误:像这样做:hotelInfo.add("" + result.getInt("hotelNo")); 而不是使用强制转换的那个! - Bart1612
请查看上面的评论,我也已经编辑了我的最后一个答案,并提供了正确的解决方案! - Bart1612

0

我想通过性能调优建议来完善上述技术解决方案。

在Java(适用于任何编程语言)中将整个SELECT输出存储到程序级变量中时,每个人都没有提及性能影响。

商业数据库的大小很容易增长到1TB,单个表通常为300GB。今天也有512GB的iPhone 14可用,以防您认为SELECT语句的输出不太可能达到300GB。

考虑到1TB的表大小,将整个SELECT输出存储到简单变量(如数组)中,将间接使用1TB的RAM。在Java中,这被认为是Java堆内存。

当然,有些成员建议将数据存储在包含setHotelName()、getHotelName()等的HotelDao类的数组中。这可能会将其Java内部内存使用量从1TB增加到2TB。

运行任何Java应用程序时,您必须在应用程序启动期间使用Java参数-Xmx(假设仅涉及堆内存)。如果您正在J2EE中托管它,则可以是Apache Tomcat启动、IBM WebSphere应用程序服务器启动、JBoss等。如果您通过报告服务器(例如Cognos、Informatica)执行此操作,则它们具有定义-Xmx参数的自己的配置。

接下来,多用户、多实例、并发访问是当今技术中的常规。如果多个用户从图形用户界面触发请求同时运行相同的SELECT语句,例如航班预订系统、报表等,那么将会有多个1TB表大小的相同SELECT语句的实例,并且在Java堆内存中还需要最少1TB的Java数组变量大小。想象一下,如果有10个并发用户,比如Expedia,将轻松创建10个这样的数组变量,每个都是1TB。如果整个程序中只有这样一个SELECT-Array设计,总变量大小将达到10TB。

问题在于,在Java应用程序启动时定义2TB的Java堆内存是不切实际的。配置10TB的Java堆内存远远超出了当今RAM最大大小的硬件限制,除非你希望向操作系统交换内存区进行大量分页操作。

无论是Eclipse Temurin还是Oracle Java 19,都不再记录默认的最大堆大小(-Xmx),但是Eclipse Java 9(https://www.eclipse.org/openj9/docs/openj9_defaults/)指出默认值为RAM大小的25%。换句话说,128GB RAM机器将分配32GB。任何一个值都不适合1TB,一旦完全使用了32GB(默认值)或整个RAM 128GB,整个Java应用程序就会立即崩溃。

当然,Windows管理员会告诉您,Windows会根据需要自动调整其页面文件。我的问题是,当在Expedia中查找酒店需要几分钟时,业务用户的体验会有多糟糕。即使Windows允许分配10TB页面文件,我们也必须考虑到由于Java应用程序员将整个SELECT输出存储在本地变量中(如果存储为Java类对象,则更大),而进行OS分页到磁盘的权衡,从而导致整体应用程序性能(最终用户体验)下降。

在整个StackOverflow.com中,通常会员们在设计JDBC应用程序时不考虑应用程序的性能,而只考虑体积大小。最新的Intel工作站单插槽CPU只能容纳128GB RAM DDR4(参考Xeon E-2388G)。我没有看到任何程序员拥有1TB RAM的顶级服务器,甚至无法处理需要10TB RAM的Java应用程序,因为这种设计。
注:支持DDR5的最新的英特尔桌面CPU Core i9第14代今天(2022年10月)的最大RAM容量为128GB RAM。参考www.crucial.com

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接