异常信息: ResultSet can not re-read row data for column 2

本文介绍了在SQL查询时,根据数据库中是否存在text类型字段,选择不同的驱动和读取方式以避免Driver]ResultSetcannotre-readrowdataforcolumn错误。通过实践方法,确保数据按顺序显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

解决方法:下面的解决方案是网上高人说的:         

          (1)如果采用jdbc-odbc驱动,那么就必须按照查询顺序来一次读取(不论有没有image或text类型)

          (2)如果采用微软提供的ms sql server jdbc driver,如果查询语句中,不存在image或text类型字段,那么可以按照无序获取
          (3)如果采用微软提供的ms sql server jdbc driver,如果查询语句中,存在image或text类型字段,那么就必须按照顺序读取,否则就会报告Driver]ResultSet can not re-read row data for column之类的错误
          (4)如果想不查询语句中有没有image或text类型字段,都可以不按照顺序获取,或重复获取。那么就必须更换驱动,改用第三方的。

         

  我的处理方法是:因为我的数据库中加了text类型的字段,所以数据必须按顺序显示。

<think>我们需要实现Java中ResultSet的分页返回。由于ResultSet通常是数据库查询的结果,它可能包含大量数据,分页返回可以减少内存消耗并提高性能。 常见的分页方法有两种: 1. 在SQL查询层面进行分页(例如,使用MySQL的LIMIT,Oracle的ROWNUM等),这样只从数据库获取当前页的数据。 2. 如果已经获取了整个ResultSet,但需要分页返回,那么可以在内存中分页(不推荐大数据量,因为会占用大量内存)。 这里我们讨论第二种情况:假设我们已经有一个ResultSet,但由于某些原因不能重新执行分页查询,我们需要在内存中分页。但是,请注意,ResultSet是单向的,并且通常不支持随机访问。因此,我们需要将数据先读入一个可随机访问的数据结构中(如List),然后再分页。 然而,更好的做法是在SQL查询时就进行分页,这样效率更高。因此,我们将分别展示两种方式。 方式一:SQL层面分页(推荐) 以MySQL为例,使用LIMIT关键字实现分页查询。 方式二:内存分页(适用于数据量不大,或者已经获取了ResultSet且无法重新查询的情况) 我们将分别给出示例代码。 注意:在实际应用中,应优先考虑方式一(SQL分页),因为方式二需要将整个结果集加载到内存中,如果数据量很大,会导致内存溢出。 下面我们分别实现两种方式: 方式一:SQL分页(以MySQL为例) 假设我们有一个用户表(user),我们想分页查询用户信息。 步骤: 1. 计算起始行号:start = (pageIndex - 1) * pageSize 2. 执行SQL:SELECT * FROM user LIMIT start, pageSize 代码示例: ```java // 假设pageIndex和pageSize是传入的参数 int start = (pageIndex - 1) * pageSize; String sql = "SELECT * FROM user LIMIT " + start + ", " + pageSize; // 执行查询,获取ResultSet ``` 方式二:内存分页 如果已经有一个ResultSet,我们可以将其数据先存储到List<Map<String, Object>>中,然后进行分页。 步骤: 1. 遍历ResultSet,将每一行转换为一个Map(或自定义对象),并添加到List中。 2. 根据pageIndex和pageSize计算分页的起始索引和结束索引,然后从List中截取子列表。 代码示例: ```java import java.sql.*; import java.util.*; public class ResultSetPager { public static List<Map<String, Object>> getPageFromResultSet(ResultSet rs, int pageIndex, int pageSize) throws SQLException { // 先将整个ResultSet转换为List List<Map<String, Object>> list = new ArrayList<>(); ResultSetMetaData metaData = rs.getMetaData(); int columnCount = metaData.getColumnCount(); while (rs.next()) { Map<String, Object> row = new HashMap<>(); for (int i = 1; i <= columnCount; i++) { row.put(metaData.getColumnLabel(i), rs.getObject(i)); } list.add(row); } // 计算分页 int start = (pageIndex - 1) * pageSize; if (start >= list.size()) { return Collections.emptyList(); // 如果起始位置超出范围,返回空列表 } int end = Math.min(start + pageSize, list.size()); return list.subList(start, end); } // 使用示例 public static void main(String[] args) { // 假设已经有一个ResultSet对象 rs try { List<Map<String, Object>> pageData = getPageFromResultSet(rs, 1, 10); // 获取第一页,每页10条 for (Map<String, Object> row : pageData) { System.out.println(row); } } catch (SQLException e) { e.printStackTrace(); } } } ``` 注意:方式二在数据量很大时性能较差,因为它需要将整个结果集加载到内存中。因此,只适用于数据量小的情况。 另外,如果使用JDBC,我们也可以使用可滚动的ResultSet(例如,使用TYPE_SCROLL_INSENSITIVE),然后使用absolute()方法直接跳转到指定行。但是,这种方式需要数据库驱动支持,并且性能可能不如SQL分页。 使用可滚动ResultSet的示例: ```java // 在创建Statement时指定可滚动 Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet rs = stmt.executeQuery("SELECT * FROM user"); // 计算绝对位置 int start = (pageIndex - 1) * pageSize + 1; // 注意:absolute方法参数从1开始 if (start <= 0) { start = 1; } // 将游标移动到起始位置 if (rs.absolute(start)) { int count = 0; do { // 处理当前行 // ... 这里可以读取数据并添加到列表或处理 count++; } while (rs.next() && count < pageSize); } ``` 但是,这种方法需要数据库驱动支持,并且不同的数据库可能有不同的实现。而且,即使使用了可滚动的ResultSet,数据库也可能在后台返回整个结果集(取决于驱动和数据库配置),所以性能可能并不理想。 综上所述,最佳实践是在SQL层面进行分页。 下面我们给出一个使用SQL分页的完整示例(以MySQL为例): ```java import java.sql.*; public class PaginationExample { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/test"; String user = "username"; String password = "password"; int pageIndex = 1; // 第一页 int pageSize = 10; // 每页10条 try (Connection conn = DriverManager.getConnection(url, user, password)) { // 计算起始行 int start = (pageIndex - 1) * pageSize; String sql = "SELECT * FROM user LIMIT ?, ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, start); pstmt.setInt(2, pageSize); ResultSet rs = pstmt.executeQuery(); // 处理结果集 while (rs.next()) { // 读取每一行数据 int id = rs.getInt("id"); String name = rs.getString("name"); // ... 其他字段 System.out.println("ID: " + id + ", Name: " + name); } } catch (SQLException e) { e.printStackTrace(); } } } ``` 解释: 1. 我们使用PreparedStatement来设置分页参数,避免SQL注入。 2. 分页参数计算:start = (pageIndex-1)*pageSize,然后使用LIMIT start, pageSize。 3. 这种方式只查询当前页的数据,效率高。 最后,根据要求,提出相关问题。 §§相关问题§§: 1. 在Java中,如何实现可滚动的ResultSet2. 除了LIMIT,其他数据库(如Oracle、SQL Server)如何实现分页查询? 3. 当数据量非常大时,如何优化分页查询的性能? 4. 在Web应用中,如何设计一个通用的分页组件?</think>### Java ResultSet 分页返回实现方案 在Java中实现ResultSet分页返回有两种主要方式:**数据库层分页**(推荐)和**应用层分页**。下面分别给出实现方案和代码示例: --- ### 方案一:数据库层分页(推荐) 直接在SQL查询中使用分页语法,只获取当前页的数据,效率最高。 ```java import java.sql.*; public class DatabasePagination { public static List<Map<String, Object>> getPageData(int page, int pageSize) { List<Map<String, Object>> result = new ArrayList<>(); String url = "jdbc:mysql://localhost:3306/mydb"; // 计算分页偏移量 int offset = (page - 1) * pageSize; try (Connection conn = DriverManager.getConnection(url, "user", "password"); PreparedStatement pstmt = conn.prepareStatement( "SELECT * FROM products ORDER BY id LIMIT ? OFFSET ?")) { pstmt.setInt(1, pageSize); pstmt.setInt(2, offset); try (ResultSet rs = pstmt.executeQuery()) { ResultSetMetaData metaData = rs.getMetaData(); int columnCount = metaData.getColumnCount(); while (rs.next()) { Map<String, Object> row = new HashMap<>(); for (int i = 1; i <= columnCount; i++) { row.put(metaData.getColumnName(i), rs.getObject(i)); } result.add(row); } } } catch (SQLException e) { e.printStackTrace(); } return result; } } ``` **代码解释:** 1. **分页参数计算**:`offset = (page-1)*pageSize` 计算需要跳过的记录数 2. **SQL分页语法**: - MySQL/PostgreSQL:`LIMIT pageSize OFFSET offset` - Oracle:`OFFSET offset ROWS FETCH NEXT pageSize ROWS ONLY` - SQL Server:`OFFSET offset ROWS FETCH NEXT pageSize ROWS ONLY` 3. **PreparedStatement**:防止SQL注入,安全设置参数 4. **结果处理**:将ResultSet转换为List<Map>结构,便于前端使用 **优点**:只传输当前页数据,内存占用小,性能最佳 --- ### 方案二:应用层分页(小数据集适用) 当无法修改SQL或处理小数据集时,可在内存中分页: ```java import java.sql.*; import java.util.*; public class MemoryPagination { public static List<Map<String, Object>> getPageData(ResultSet rs, int page, int pageSize) throws SQLException { List<Map<String, Object>> allData = new ArrayList<>(); ResultSetMetaData metaData = rs.getMetaData(); int columnCount = metaData.getColumnCount(); // 1. 读取全部数据到内存 while (rs.next()) { Map<String, Object> row = new LinkedHashMap<>(); for (int i = 1; i <= columnCount; i++) { row.put(metaData.getColumnName(i), rs.getObject(i)); } allData.add(row); } // 2. 计算分页范围 int start = (page - 1) * pageSize; int end = Math.min(start + pageSize, allData.size()); // 3. 返回分页数据 if (start > allData.size()) { return Collections.emptyList(); } return allData.subList(start, end); } } ``` **代码解释:** 1. **全量读取**:先将ResultSet所有数据加载到内存 2. **分片计算**:计算分页的起止索引 3. **子列表截取**:使用`List.subList()`获取当前页数据 **缺点**:大数据集时内存消耗大,性能差 --- ### 最佳实践建议 1. **优先使用数据库分页**(方案一),特别是超过1000条记录时 2. **分页参数校验**: ```java if (page < 1) page = 1; if (pageSize > 100) pageSize = 100; // 防止过大分页 ``` 3. **返回分页元信息**: ```java public class PageResult<T> { private int currentPage; private int totalPages; private long totalItems; private int pageSize; private List<T> items; // getters/setters } ``` 4. **获取总记录数**: ```sql SELECT COUNT(*) FROM products ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值