gpt4 book ai didi

java - 程序在检索到包含 CLOB 的 100 行后挂起

转载 作者:塔克拉玛干 更新时间:2023-11-02 18:58:44 26 4
gpt4 key购买 nike

我正在从“远程”H2 数据库(实际上在本地驱动器上,但使用 tcp 访问它)中的表中检索一个文本列 (CLOB),在检索前 100 行后,程序在检索下一个时挂起结果集的行。另一方面,如果我访问与嵌入式数据库相同的数据库,则没有问题。如果我尝试使用 H2 的控制台应用程序使用服务器(即 tcp)方法访问数据库来显示表的行,则会收到以下错误消息:

IO Exception: "java.io.IOException: org.h2.message.DbException: The object is already closed [90007-164]"; 
"lob: null table: 14 id: 1" [90031-164] 90031/90031

这是程序。如果我取消注释掉设置系统属性的调用,程序就会运行。我还尝试过使用字符流或简单地调用由常量 USE_STREAM 控制的 getString 来检索列。结果没有区别:

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

public class Jdbc4
{
private static final boolean USE_STREAM = false;

public static void main(String[] args) throws Exception
{
//System.setProperty("h2.serverResultSetFetchSize", "50");
Connection conn = null;
try {
Class.forName("org.h2.Driver").newInstance();
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/file:C:/h2/db/test/test;IFEXISTS=TRUE", "sa", "");
Statement stmt = conn.createStatement();
String sql = "select select_variables from ipm_queues";
ResultSet rs = stmt.executeQuery(sql);
int count = 0;
while (rs.next()) {
++count;
String s;
if (USE_STREAM) {
Clob clob = rs.getClob(1);
Reader rdr = clob.getCharacterStream();
char[] cbuf = new char[1024];
StringBuffer sb = new StringBuffer();
int len;
while ((len = rdr.read(cbuf, 0, cbuf.length)) != -1)
sb.append(cbuf, 0, len);
rdr.close();
s = sb.toString();
clob.free();
}
else
s = rs.getString(1);
System.out.println(count + ": " + s);
}
}
finally {
if (conn != null)
conn.close();
}
}
}

这里是建表的DDL(可以看到原来是MySql的表):

CREATE TABLE `ipm_queues` (
`oid` bigint NOT NULL,
`queue_id` varchar(256) NOT NULL,
`store_id` bigint NOT NULL,
`creation_time` datetime NOT NULL,
`status` bigint NOT NULL,
`deleted` bigint NOT NULL,
`last_mod_time` datetime NOT NULL,
`queue_name` varchar(128),
`select_variables` text,
`where_clause` text,
`from_table` varchar(128),
`order_by` varchar(256),
`from_associate_table` varchar(256),
`from_view` varchar(128)
);

ALTER TABLE ipm_queues
ADD CONSTRAINT ipm_queues_pkey PRIMARY KEY (oid);

CREATE UNIQUE INDEX ipm_queues_key_idx ON ipm_queues(queue_id, store_id);

CREATE INDEX ipm_queues_str_idx ON ipm_queues(store_id);

最佳答案

我相信我了解挂起的原因。我研究了使用值为 600 的 h2.serverResultSetFetchSize 的最简单情况,这比我知道的 523 行要多。正如我提到的,我可以检索前 3 行(单个 CLOB 列),然后我要么挂起检索第 4 行,要么我得到一个“对象已经关闭”的异常。

事实证明,包含前三列的实际字符串的长度似乎相当短,类 org.h2.value.ValueLobDb 中的方法 getInputStream 已经有了数据,并且只返回一个基于该数据构造的 ByteArrayInputStream。第 4 行的数据仍在服务器端,因此必须构建实际的 RemoteInputStream 来处理从服务器端 LOB 获取数据。

这似乎是问题所在:类 org.h2.server.TcpServerThread 正在将这些 LOB 缓存在 SmallLRUCache 的实例中。此缓存似乎旨在仅维护最近最少引用的 LOB!此缓存的默认大小由系统属性 h2.serverCachedObjects 给出,默认为 64,而默认提取大小为 100。因此即使我没有覆盖默认的 h2.serverResultSetFetchSize 属性,如果我的所有行都足够大需要缓存 LOB 的列,任何大于 64 的提取大小都会导致代表第一行的 LOB 从缓存中刷新,我什至无法检索第一行。

LRU 缓存似乎是用于保存 Activity 结果集中的 LOB 的错误结构。当然,默认缓存大小小于默认提取大小似乎不太理想。

关于java - 程序在检索到包含 CLOB 的 100 行后挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9779324/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com