2012-05-23 181 views
4

我的問題是:如何在CLOB插入(或在查詢中執行任何操作)時遇到ORA-01704: string literal too long錯誤?將CLOB插入到Oracle數據庫中

我想有這樣的查詢:

INSERT ALL 
    INTO mytable VALUES ('clob1') 
    INTO mytable VALUES ('clob2') --some of these clobs are more than 4000 characters... 
    INTO mytable VALUES ('clob3') 
SELECT * FROM dual; 

當我嘗試將其與實際值雖然我得到ORA-01704: string literal too long回來。這是非常明顯的,但我如何插入clobs(或用clob執行任何語句)?

我試過看這question,但我不認爲它有我在找什麼。我有的clobs在List<String>,我遍歷他們做出聲明。因爲這是我的代碼如下:

private void insertQueries(String tempTableName) throws FileNotFoundException, DataException, SQLException, IOException { 
String preQuery = " into " + tempTableName + " values ('"; 
String postQuery = "')" + StringHelper.newline; 
StringBuilder inserts = new StringBuilder("insert all" + StringHelper.newline); 
List<String> readQueries = getDomoQueries(); 
for (String query : readQueries) { 
    inserts.append(preQuery).append(query).append(postQuery); 
} 
inserts.append("select * from dual;"); 

DatabaseController.getInstance().executeQuery(databaseConnectionURL, inserts.toString()); 

}

public ResultSet executeQuery(String connection, String query) throws DataException, SQLException { 
    Connection conn = ConnectionPool.getInstance().get(connection); 
    Statement stmt = conn.createStatement(); 
    ResultSet rs = stmt.executeQuery(query); 
    conn.commit(); 
    ConnectionPool.getInstance().release(conn); 
    return rs; 
} 
+1

而是動態SQL和建設有字符串文字的INSERT語句,你嘗試使用'PreparedStatement'和它的'setClob()'方法? – QuantumMechanic

回答

7

你使它方式複雜。

使用PreparedStatement和addBatch()在你的列表中的每個CLOB:

String sql = "insert into " + tempTableName + " values (?)"; 
PreparedStatement stmt = connection.prepareStatement(sql); 
for (String query : readQueries) { 
    stmt.setCharacterStream(1, new StringReader(query), query.lenght()); 
    stmt.addBatch(); 
} 
stmt.exececuteBatch(); 

沒有加上漏出的字符串亂搞,隨着文字的長度沒有問題,沒有必要創建臨時的CLOB。最可能與使用單個INSERT ALL語句一樣快。

如果您使用的是當前驅動程序(> 10.2),那麼我認爲setCharacterStream()調用和Reader的創建也不是必需的。一個簡單的setString(1, query)很可能會工作。

2

你需要使用綁定變量,而不是建立使用字符串連接的SQL語句。從安全性,性能和健壯性的角度來看,這將會有所幫助,因爲它可以降低SQL注入攻擊的風險,減少Oracle花費在硬解析SQL語句上的時間,並消除潛在的潛在影響是字符串中的一個特殊字符,它會導致生成無效的SQL語句(即單引號)。

我希望你要像

private void insertQueries(String tempTableName) throws FileNotFoundException, DataException, SQLException, IOException { 
    String preQuery = " into " + tempTableName + " values (?)" + StringHelper.newline; 
    StringBuilder inserts = new StringBuilder("insert all" + StringHelper.newline); 
    List<String> readQueries = getDomoQueries(); 
    for (String query : readQueries) { 
    inserts.append(preQuery); 
    } 
    inserts.append("select * from dual"); 

    Connection conn = ConnectionPool.getInstance().get(connection); 
    PreparedStatement pstmt = conn.prepareStatement(
     inserts); 
    int i = 1; 
    for (String query : readQueries) { 
    Clob clob = CLOB.createTemporary(conn, false, oracle.sql.CLOB.DURATION_SESSION); 
    clob.setString(i, query); 
    pstmt.setClob(i, clob); 
    i = i + 1; 
    } 
    pstmt.executeUpdate(); 
} 
+0

我認爲這應該工作,除了'setClob'方法採取clob不是一個字符串。在另一個問題中,它顯示clob的創建如下所示:'oracle.sql.CLOB.createTemporary(connection,false,oracle.sql.CLOB.DURATION_SESSION);'是否正確? – kentcdodds

+0

@kentcdodds - 我相信(我目前沒有與我一起開發Java開發環境) –

+0

您還可以爲Oracle CLOB列執行setString()。 Oracle JDBC驅動程序非常聰明,可以執行轉換。 – GriffeyDog

2

BLOB(二進制大對象)和CLOB(字符大對象)是特殊的數據類型,可以以對象或文本的形式保存大塊數據。 Blob和Clob對象將對象的數據作爲流保存到數據庫中。

一個例子的代碼:

public class TestDB { 
    public static void main(String[] args) { 
     try { 
      /** Loading the driver */ 
      Class.forName("com.oracle.jdbc.Driver"); 

      /** Getting Connection */ 
      Connection con = DriverManager.getConnection("Driver URL","test","test"); 

      PreparedStatement pstmt = con.prepareStatement("insert into Emp(id,name,description)values(?,?,?)"); 
      pstmt.setInt(1,5); 
      pstmt.setString(2,"Das"); 

      // Create a big CLOB value...AND inserting as a CLOB 
      StringBuffer sb = new StringBuffer(400000); 

      sb.append("This is the Example of CLOB .."); 
      String clobValue = sb.toString(); 

      pstmt.setString(3, clobValue); 
      int i = pstmt.executeUpdate(); 
      System.out.println("Done Inserted"); 
      pstmt.close(); 
      con.close(); 

      // Retrive CLOB values 
      Connection con = DriverManager.getConnection("Driver URL","test","test"); 
      PreparedStatement pstmt = con.prepareStatement("select * from Emp where id=5"); 
      ResultSet rs = pstmt.executeQuery(); 
      Reader instream = null; 

      int chunkSize; 
      if (rs.next()) { 
       String name = rs.getString("name"); 
       java.sql.Clob clob = result.getClob("description") 
       StringBuffer sb1 = new StringBuffer(); 

       chunkSize = ((oracle.sql.CLOB)clob).getChunkSize(); 
       instream = clob.getCharacterStream(); 
       BufferedReader in = new BufferedReader(instream); 
       String line = null; 
       while ((line = in.readLine()) != null) { 
        sb1.append(line); 
       } 

       if (in != null) { 
        in.close(); 
       } 

       // this is the clob data converted into string 
       String clobdata = sb1.toString(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+1

感謝您提供回覆。下一次,請使用邏輯縮進方案格式化您的代碼。我會爲你編輯你的文章。 (提示:如果你的代碼非常實用,你會得到更多的選票。) – bohney

2

Oracle document

必須牢記對大型數據輸入模式的自動切換以下。 有三種輸入模式,如下所示:直接綁定,流綁定和LOB綁定。

對於PL/SQL語句

的setBytes和將優先考慮setBinary流方法使用直接用於小於32767個字節的數據綁定。

setBytes和setBinaryStream方法對大於32766字節的數據使用LOB綁定。

setString,setCharacterStream和setAsciiStream方法對數據庫字符集中小於32767字節的數據使用直接綁定。

setString,setCharacterStream和setAsciiStream方法對數據庫字符集中大於32766字節的數據使用LOB綁定。

存在於oracle.jdbc.OraclePreparedStatement接口中的setBytesForBlob和setStringForClob方法對任何數據大小使用LOB綁定。

關注是把文件內容到PLSQL過程的輸入參數CLOB一個例子:

public int fileToClob(FileItem uploadFileItem) throws SQLException, IOException 
    { 
    //for using stmt.setStringForClob method, turn the file to a big String 
    FileItem item = uploadFileItem; 
    InputStream inputStream = item.getInputStream(); 
    InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  
    StringBuffer stringBuffer = new StringBuffer(); 
    String line = null; 

    while((line = bufferedReader.readLine()) != null) { //Read till end 
     stringBuffer.append(line); 
     stringBuffer.append("\n"); 
    } 

    String fileString = stringBuffer.toString(); 

    bufferedReader.close();   
    inputStreamReader.close(); 
    inputStream.close(); 
    item.delete(); 

    OracleCallableStatement stmt; 

    String strFunction = "{ call p_file_to_clob(p_in_clob => ?)}"; 

    stmt= (OracleCallableStatement)conn.prepareCall(strFunction);  

    try{  
     SasUtility servletUtility = sas.SasUtility.getInstance(); 

     stmt.setStringForClob(1, fileString); 

     stmt.execute(); 

    } finally {  
     stmt.close(); 
    } 
    } 
相關問題