jdbc或PL/SQL中通过insert语句插入数据时,如果有CLOB字段,且插入的数据长度超过4000,且会报ORA-01704字符串文字太长的错。
一.java jdbc方式处理
对于CLOB字段,其实就需要通过流的方式处理,如下是从网上搜集的一些处理方式。
1.CharacterStream方式
/* --建表语句如下: create table t_clob( id varchar2(32) primary key, clobfield CLOB ); */ /** * 读取CLOB字段的代码示例 */ public void readClob() { //自定义的数据库连接管理类 Connection conn = DbManager.getInstance().getConnection(); try { PreparedStatement stat = conn .prepareStatement("select clobfield from t_clob where id='1'"); ResultSet rs = stat.executeQuery(); if (rs.next()) { oracle.sql.CLOB clob = (oracle.sql.CLOB) rs .getClob("clobfield"); String value = clob.getSubString(1, (int) clob.length()); System.out.println("CLOB字段的值:" + value); } conn.commit(); } catch (SQLException e) { e.printStackTrace(); } DbManager.getInstance().closeConnection(conn); } /** * 写入、更新CLOB字段的代码示例 */ public void writeClob() { //自定义的数据库连接管理类 Connection conn = DbManager.getInstance().getConnection(); try { conn.setAutoCommit(false); // 1.这种方法写入CLOB字段可以。 PreparedStatement stat = conn .prepareStatement("insert into t_clob (id,clobfield) values(sys_guid(),?)"); String clobContent = "This is a very very long string"; StringReader reader = new StringReader(clobContent); stat.setCharacterStream(1, reader, clobContent.length()); stat.executeUpdate(); // 2.使用类似的方法进行更新CLOB字段,则不能成功 // stat.close(); // stat =null; // stat = // conn.prepareStatement("update t_clob set clobfield=? where id=1"); // stat.setCharacterStream(1, reader, clobContent.length()); // stat.executeUpdate(); // 3.需要使用for update方法来进行更新, // 但是,特别需要注意,如果原来CLOB字段有值,需要使用empty_clob()将其清空。 // 如果原来是null,也不能更新,必须是empty_clob()返回的结果。 stat = conn .prepareStatement("select clobfield from t_clob where id='1' for update"); ResultSet rs = stat.executeQuery(); if (rs.next()) { oracle.sql.CLOB clob = (oracle.sql.CLOB) rs .getClob("clobfield"); Writer outStream = clob.getCharacterOutputStream(); char[] c = clobContent.toCharArray(); outStream.write(c, 0, c.length); outStream.flush(); outStream.close(); } conn.commit(); } catch (SQLException | IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } DbManager.getInstance().closeConnection(conn); }
2.BufferedReader方式
CLOB用于存储大量的字符数据,读取CLOB的JDBC代码如下所示。
import java.sql.*; import java.io.*; public class ReadClob { public static void main(String[] args) { PreparedStatement pstmt = null; ResultSet rset = null; BufferedReader reader = null; Connection conn = null; String driver = "oracle.jdbc.driver.OracleDriver"; String strUrl = "jdbc:oracle:[email protected]:1521:ORCL"; try { Class.forName(driver); conn = DriverManager.getConnection(strUrl, "scott", "tiger"); pstmt = conn .prepareStatement("select v_clob form ord where ORD_id =?"); pstmt.setInt(1, 1); rset = pstmt.executeQuery(); while (rset.next()) { Clob clob = rset.getClob(1);// java.sql.Clob类型 reader = new BufferedReader(new InputStreamReader(clob .getAsciiStream())); String line = null; while ((line = reader.readLine()) != null) { System.out.println(line); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
程序代码从结果集中获取CLOB字段,再将其转化为IO流进行读取。那么,JDBC将大量自读数据写入CLOB字段的操作需要首先用“for update”字句查找CLOB字段,然后从结果集中获取CLOB字段并转化为oracle.sql.CLOB类型进行写入操作。
//写入操作 String stmtString = "select v_clob form ord where ord_id =? for update"; pstmt = conn.prepareStatement(stmtString); pstmt.setInt(1, 2); rset = pstmt.executeQuery(); while(rset.next()){ //造型为oracle.sql.CLOB CLOB clob = (CLOB)rset.getClob(1); String newClobDate = new String("NEW CLOOB DATE"); Writer writer = clob.getCharacterOutputStream(); //OutStream writer = clob.getAsciiOutputStream(); writer.write(newClobDate); }
3.生成一个clob对象,通过预处理的setClob达到插入更新的目的。
方法一:
Connection con = dbl.loadConnection(); strSql = "insert into table1(id,a) values (1,EMPTY_CLOB())"; dbl.executeSql(strSql); String str2 = "select a from table1 where id=1"; ResultSet rs = dbl.openResultSet(str2); if(rs.next()){ CLOB c = ((OracleResultSet)rs).getCLOB("a"); c.putString(1, "长字符串"); String sql = "update table1 set a=? where id=1"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setClob(1, c); pstmt.executeUpdate(); pstmt.close(); } con.commit();
方法二:
Connection con = dbl.loadConnection(); CLOB clob = oracle.sql.CLOB.createTemporary(con, false,oracle.sql.CLOB.DURATION_SESSION); clob.putString(1, "长字符串"); Sql1 = "update table1 set a=? where id=1"; PreparedStatement pst = con.prepareStatement(Sql1); pst.setClob(1, clob); pst.executeUpdate(); pst.close(); con.commit();
二.sql方式
当通过insert语句直接插入大量字符串(主要是html的内容),超过4000字符时候,就会报:ORA-01489: 字符串连接的结果过长。
虽然字段是clob,足以存储,但是通过这种直接插入的时候,因为没有强制指定带插入字符串为clob类型,oracle会把插入的字符串作为 “字符串类型”处理,由于oracle有最大字符串限制(不超过4000个字符),所以会报错。
解决思路:指定待插入字符串类型为clob,可以使用过程或存储过程。
实例:
DECLARE REALLYBIGTEXTSTRING CLOB := '待插入的海量字符串'; BEGIN INSERT INTO test_table VALUES('test', REALLYBIGTEXTSTRING, '0'); end ; / commit;
补充:插入html内容,可能含有空格 ,字符&是oracle的关键字,因此插入之前要转义,如:'||chr(38)||'nbsp;