【问题标题】:Managing Java CLOB with JBoss and Tomcat使用 JBoss 和 Tomcat 管理 Java CLOB
【发布时间】:2015-05-19 00:37:15
【问题描述】:

使用 tomcat 和 mysql 在 webapps 中处理 clob 似乎很容易。 对于下面的示例,我们假设我们有一个表 'mytable',其中包含一个 clob 'myclob' 和一个键 'id' 这是一个如何将字节数组放入 clob 的示例:

Connection           conn = null;
PreparedStatement    stmt = null;
ByteArrayInputStream  bis = null;
try {
    if (mydatasource != null)
        conn = mydatasource.getConnection();
    StringBuffer sb=new StringBuffer("update mytable set myclob = ? where id = ?");
    bis=new ByteArrayInputStream(myArrayOfBytes);
    stmt.setBinaryStream( 1, bis);
    stmt.setString(2, "myId");
    stmt.executeUpdate();
} catch(Exception ex){
    ex.printStackTrace();
} finally {
    try{bis.close();} catch (Exception x) {;}
    try{stmt.close();} catch (Exception x) {;}
    try{conn.close();} catch (Exception x) {;}
}

当我尝试将我的 webapp 移动到 jboss 5.0 和 Oracle db 时,困难在于:

ORA-01461: 只能绑定 LONG 值以插入到 LONG 列中

问题是:如何解决这个错误(还认为方法'createClob()'不起作用?

【问题讨论】:

  • 你的问题是什么?

标签: java oracle jdbc


【解决方案1】:

使用PreparedStatement#setClob 而不是setBinaryStream。另外,请确保您在 oracle 表中的字段也是 CLOB。

要创建Clob 的实例,请使用Connection#createClob

【讨论】:

    【解决方案2】:

    这个问题与 SO 上的许多问题重复。通常问题是 BLOB/CLOB 不是 Java 对象,不能位于 Java 堆上。它类似于一个文件,它存在于数据库中。而且只能由数据库创建。

    因此有这些方法来创建 CLOB

    • Connection.createClob(),这将需要到数据库的循环,并将在 TEMPorary 表空间中创建 CLOB。当在下一个查询中使用此 clob 时,必须将数据从一个磁盘位置复制到另一个磁盘位置(在最坏的情况下)
    • INSERT insert into T(it, file) values(t_seq.nextval, empty_blob()) returning id, file into :id, :file; 从 Oracle 的角度来看,此构造是最佳选择。更少的往返,无需在 TEMP 表空间中分配空间。但不幸的是,returnng 子句是专有的 SQL 扩展,不受 JDBC 标准支持
    • 2 步方法。首先使用 file=empty_blob() 函数插入/更新行,然后在第二步中通过 SELECT FOR UPDATEstatment 返回新创建的 LOB 的句柄。

    至少在 Oracle 的情况下,您不能将 LOB 视为只是另一个绑定变量占位符。在这种情况下,您依赖于一些隐式数据类型转换,这是不安全的。

    【讨论】:

    • 第一个使用 jboss 5.0、liferay 和 oracle 11 的解决方案导致异常,我发现第二个解决方案非常有趣,即使最后我选择了最后一个来保持与我的第一个软件集的兼容性( tomcat+mysql).
    【解决方案3】:

    经过一番搜索,解决方法是:
    1- 使用“选择更新”查询获取 clob
    2- 将数据写入 clob
    3- 使用执行语句更新表

    这里是代码

    Connection           conn = null;
    PreparedStatement    stmt = null;
    try {
        if (infodatasource != null)
        conn = infodatasource.getConnection();
    
        //Update to prevent null pointer exceptions during next query
        stmt = conn.prepareStatement("UPDATE mytable set myclob=empty_clob() WHERE id = ?");
        stmt.setString(1, idPoi);
        stmt.executeUpdate();
    
        stmt = conn.prepareStatement("SELECT myclob FROM mytable WHERE id = ? FOR UPDATE");
        stmt.setString(1, idPoi);
        ResultSet rs = stmt.executeQuery();
        Clob myclob=null;
        if(rs.next()) {
        myclob=rs.getClob("CARTASER");
        }
    
        OutputStream writer = myclob.setAsciiStream(0L);
        writer.write(myArrayOfBytes);
        writer.flush();
        writer.close();
    
        stmt = conn.prepareStatement("UPDATE mytable SET myclob = ? WHERE id = ?");
        stmt.setClob(1, myclob);
        stmt.setString(2, "myid");
        return stmt.execute(); //Note: explicit commit required if autocommit is off
    } catch(Exception ex){
        ex.printStackTrace();
        //out.println("Cannot get connection: " + ex);
    } finally {
        try{stmt.close();} catch (Exception x) {;}
        try{conn.close();} catch (Exception x) {;}
    }
    return false;
    

    【讨论】:

    • 看来您还没有阅读我的回答。您根本不需要选择和重写 Clob 对象,除非您的 JDBC 驱动程序非常旧。
    • 对不起 Luigi,但我没有找到任何其他可行的解决方案,我的问题和我的回答是与其他用户分享可能解决方案的一种方式,一种不浪费一天搜索和搜索。您建议的方法会产生另一个异常:必须创建 clob,并且方法 connection.createClob() 会导致此异常。
    • 我对类似的解决方案进行了一些研究,并在发布答案后不到 5 分钟得到了结果。你只是想重新发明轮子。
    • 好吧,您至少可以在问题中发布异常。您无法针对您的特定案例解决它的事实并不意味着它不适用于其他所有人。
    • 您示例中的第二次更新是 useles。当您将数据写入从数据库返回的 LOB 定位器时,数据已经存储。另一方面,您应该在连接之前调用 conn.commit()。
    猜你喜欢
    • 1970-01-01
    • 2013-08-02
    • 2017-06-10
    • 1970-01-01
    • 2012-08-14
    • 2014-12-24
    • 2013-11-23
    • 1970-01-01
    • 2014-07-30
    相关资源
    最近更新 更多