ORA-22922:从标量子查询获取 CLOB 值时,Oracle 18c 中不存在 LOB 值

问题描述 投票:0回答:1

以下语句在 Oracle 18c 上不起作用,但在 Oracle 23ai 上运行良好:

try (Statement s = connection.createStatement()) {
    try (ResultSet rs = s.executeQuery(
        """
        SELECT (SELECT to_clob('123412341234') x FROM dual)
        FROM dual
        CONNECT BY LEVEL <= 20
        """
    )) {
        while (rs.next()) {
            System.out.println(rs.getString(1));
        }
    }
}

成功获取前 10 行后,出现以下错误:

123412341234
123412341234
123412341234
123412341234
123412341234
123412341234
123412341234
123412341234
123412341234
123412341234
ORA-22922: 不存在的 LOB 值

它似乎并不严格与 ojdbc 相关,因为我也可以在 SQL*Plus 中重现类似的问题:

SQL> SELECT (SELECT to_clob('123412341234') x FROM dual)
  2  FROM dual
  3  CONNECT BY LEVEL <= 11;

(SELECTTO_CLOB('123412341234')XFROMDUAL)
--------------------------------------------------------------------------------
123412341234
ERROR:
ORA-22922: nonexistent LOB value

这是一个已知的错误吗?如何解决它?

java oracle jdbc clob ojdbc
1个回答
0
投票

虽然我不知道这个错误本身(它一定是,没有理由不工作,显然,它已在 23ai 中修复),但这里有一些解决方法,知道这与标量子查询有关:

连接一个空的
CLOB

此查询没有暴露这样的问题:

SELECT (SELECT to_clob('123412341234') x FROM dual) || to_clob('')
FROM dual
CONNECT BY LEVEL <= 20

将标量子查询包装在
to_clob()
函数调用中

这似乎也有效:

SELECT to_clob((SELECT to_clob('123412341234') x FROM dual))
FROM dual
CONNECT BY LEVEL <= 20

增加 ojdbc 获取大小

这可行,但只是将问题推迟到后面的一行:

try (Statement s = connection.createStatement()) {
    s.setFetchSize(1000);
    try (ResultSet rs = s.executeQuery(
        """
        SELECT (SELECT to_clob('123412341234') x FROM dual)
        FROM dual
        CONNECT BY LEVEL <= 20
        """
    )) {
        while (rs.next()) {
            System.out.println(rs.getString(1));
        }
    }
}

获取 JDBC
Clob
值,并延迟
Clob.free()
调用

此技术类似于手动规避获取大小对查询行为的影响,分配

Clob
资源,并延迟释放资源直到查询执行结束:

try (Statement s = connection.createStatement()) {
    try (ResultSet rs = s.executeQuery(
        """
        SELECT (SELECT to_clob('123412341234') x FROM dual)
        FROM dual
        CONNECT BY LEVEL <= 20
        """
    )) {
        List<Clob> clobs = new ArrayList<>();

        while (rs.next()) {
            Clob clob = rs.getClob(1);
            clobs.add(clob);
            System.out.println(clob.getSubString(1, (int) clob.length()));
        }

        for (Clob clob : clobs)
            clob.free();
    }
}

提前释放

Clob
值似乎又会带来问题。

按获取大小延迟
Clob
释放

拥有与 JDBC 获取大小大小完全相同的未释放

Clob
值的缓冲区似乎也可以工作。这似乎比上述将大量数据缓存在 ojdbc 中的方法更好:

try (Statement s = connection.createStatement()) {
    try (ResultSet rs = s.executeQuery(
        """
        SELECT (SELECT to_clob('123412341234') x FROM dual)
        FROM dual
        CONNECT BY LEVEL <= 100
        """
    )) {
        Deque<Clob> clobs = new ArrayDeque<>();

        while (rs.next()) {
            Clob clob = rs.getClob(1);
            clobs.add(clob);
            System.out.println(clob.getSubString(1, (int) clob.length()));

            int size = clobs.size() - s.getFetchSize();
            while (size --> 0)
                clobs.pollFirst().free();
        }

        for (Clob clob : clobs)
            clob.free();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.