在本机查询中设置 Clob 值

Setting a Clob value in a native query

Oracle 数据库。

Spring 使用 Hibernate 的 JPA。

我无法将 Clob 值插入本机 sql 查询。 调用查询的代码如下:

@SuppressWarnings("unchecked")
public List<Object[]> findQueryColumnsByNativeQuery(String queryString, Map<String, Object> namedParameters)
{
    List<Object[]> result = null;

    final Query query = em.createNativeQuery(queryString);

    if (namedParameters != null)
    {
        Set<String> keys = namedParameters.keySet();
        for (String key : keys)
        {
            final Object value = namedParameters.get(key);

            query.setParameter(key, value);

        }
    }
    query.setHint(QueryHints.HINT_READONLY, Boolean.TRUE);
    result = query.getResultList();
    return result;
}

查询字符串的格式为

SELECT  COUNT  (  DISTINCT  ( <column>  )  )   FROM  <Table> c  where (exact ( <column> ,  (:clobValue),  null  )  =  1 )

其中“(exact ( , (:clobValue), null ) = 1 )”是一个函数,"clobValue" 是一个 Clob。

我可以按如下方式调整查询:

SELECT  COUNT  (  DISTINCT  ( <column>  )  )   FROM  <Table> c  where (exact ( <column> ,  to_clob((:stringValue)),  null  )  =  1 )

其中 "stringValue" 是一个字符串,但显然这只能达到最大 sql 字符串大小 (4000),我需要传递的远不止于此。

  1. 我尝试使用

    方法将 Clob 值作为 java.sql.Clob 传递

    最终 Clob clobValue = org.hibernate.engine.jdbc.ClobProxy.generateProxy(stringValue);

这导致
java.io.NotSerializableException:org.hibernate.engine.jdbc.ClobProxy

  1. 我尝试使用

    序列化 Clob

    最终 Clob clob = org.hibernate.engine.jdbc.ClobProxy.generateProxy(stringValue);
    最终 Clob clobValue = SerializableClobProxy.generateProxy(clob);

但这似乎向 "exact" 函数提供了错误类型的参数,导致
(org.hibernate.engine.jdbc.spi.SqlExceptionHelper:144) - SQL错误:29900,SQL状态:99999 (org.hibernate.engine.jdbc.spi.SqlExceptionHelper:146) - ORA-29900: 运算符绑定不存在 ORA-06553: PLS-306: 调用 'EXACT'

时参数的数量或类型错误
  1. 阅读了一些 post 关于将 Clob 与实体一起使用的内容后,我尝试传入一个字节 [] 但这也提供了错误的参数类型
    (org.hibernate.engine.jdbc.spi.SqlExceptionHelper:144) - SQL 错误:29900,SQL状态:99999 (org.hibernate.engine.jdbc.spi.SqlExceptionHelper:146) - ORA-29900: 运算符绑定不存在 ORA-06553: PLS-306: 调用 'EXACT'

  2. 时参数的数量或类型错误
  3. 我也可以将值作为字符串传递,只要它不破坏最大字符串值

我看到一个post(Using function in where clause with clob parameter)似乎暗示唯一的方法是使用"plain old JDBC"。这不是一个选择。 我正面临一个艰难的截止日期,所以非常欢迎任何帮助。

在这种情况下,似乎需要为 Hibernate 显式设置参数类型。以下代码对我有用:

Clob clob = entityManager
    .unwrap(Session.class)
    .getLobHelper()
    .createClob(reader, length);
int inserted = entityManager
    .unwrap(org.hibernate.Session.class)
    .createSQLQuery("INSERT INTO EXAMPLE ( UUID,  TYPE,  DATA) VALUES         (:uuid, :type, :data)")
    .setParameter("uuid", java.util.Uuid.randomUUID(), org.hibernate.type.UUIDBinaryType.INSTANCE)
    .setParameter("type", java.util.Uuid.randomUUID(), org.hibernate.type.StringType.INSTANCE)
    .setParameter("data", clob, org.hibernate.type.ClobType.INSTANCE)
    .executeUpdate();

类似的解决方法可用于 Blob。

恐怕您对 Oracle 中的 CLOB 的假设是错误的。在 Oracle 中,CLOB 定位器类似于文件句柄。而这样的句柄只能由数据库创建。所以你不能简单地将 CLOB 作为绑定变量传递。 CLOB 一定与数据库存储有某种关系,因为它最多可以占用 176TB,而类似的东西不能保存在 Java 堆中。

所以通常的方法是调用数据库函数 empty_clob() 或 dbms_lob.create_temporary(以某种形式)。然后,即使您认为它是 "IN" 参数,您也会从 数据库中获得一个 clob 。然后您可以将任意多的数据写入该定位器(句柄、CLOB),然后您可以将此 CLOB 用作查询的参数。

如果不遵循此模式,您的代码将无法运行。不管你用JPA、SpringBatch还是planJDBC。这个约束是数据库给的。

答案:谢谢你们的回答。当我前段时间解决这个问题时,我应该更新这个。最后我用了JDBC,问题烟消云散!