How to write / update Oracle blob in a reliable way?

前端 未结 3 740
盖世英雄少女心
盖世英雄少女心 2020-11-28 09:09

I\'m trying to write and update a pdf document in a blob column but I\'m just able to update the blob only writing more data than the previous stored data. If I try to updat

相关标签:
3条回答
  • 2020-11-28 09:15

    FWIW, for something that fits in memory, I found I could simply pass in a byte array as the prepared statement parameter, rather than going through the "stream" rigor morale (or worse Oracle specific/suggested things)

    Using a Spring "JDBC template" wrapper (org.springframework.jdbc.core.JdbcTemplate) to put the contents of a "large" (or not) string into a BLOB column, the code is something like the following:

    jdbc.update( "insert into a_table ( clob_col ) values ( ? )", largeStr.getBytes() );
    

    There is no step 2.

    0 讨论(0)
  • 2020-11-28 09:33

    It's a lot easier:

    PreparedStatement pstmt =
      conn.prepareStatement("update blob_table set blob = ? where id = ?");
    File blob = new File("/path/to/picture.png");
    FileInputStream in = new FileInputStream(blob);
    
    // the cast to int is necessary because with JDBC 4 there is 
    // also a version of this method with a (int, long) 
    // but that is not implemented by Oracle
    pstmt.setBinaryStream(1, in, (int)blob.length()); 
    
    pstmt.setInt(2, 42);  // set the PK value
    pstmt.executeUpdate();
    conn.commit();
    pstmt.close();
    

    It works the same when using an INSERT statement. No need for empty_blob() and a second update statement.

    0 讨论(0)
  • 2020-11-28 09:35

    In addition to a_horse_with_no_name's answer (which relies on PreparedStatement.setBinaryStream(...) API), there're at least two more options for BLOBs, and 3 more for CLOBs and NCLOBs:

    1. Explicitly create a LOB, write to it, and use PreparedStatement.setBlob(int, Blob):

      int insertBlobViaSetBlob(final Connection conn, final String tableName, final int id, final byte value[])
      throws SQLException, IOException {
          try (final PreparedStatement pstmt = conn.prepareStatement(String.format("INSERT INTO %s (ID, VALUE) VALUES (?, ?)", tableName))) {
              final Blob blob = conn.createBlob();
              try (final OutputStream out = new BufferedOutputStream(blob.setBinaryStream(1L))) {
                  out.write(value);
              }
      
              pstmt.setInt(1, id);
              pstmt.setBlob(2, blob);
              return pstmt.executeUpdate();
          }
      }
      
    2. Update an empty LOB (inserted via DBMS_LOB.EMPTY_BLOB() or DBMS_LOB.EMPTY_CLOB()) via SELECT ... FOR UPDATE. This is Oracle-specific and requires two statements executed instead of one. Additionally, this is what you were trying to accomplish in the first place:

      void insertBlobViaSelectForUpdate(final Connection conn, final String tableName, final int id, final byte value[])
      throws SQLException, IOException {
          try (final PreparedStatement pstmt = conn.prepareStatement(String.format("INSERT INTO %s (ID, VALUE) VALUES (?, EMPTY_BLOB())", tableName))) {
              pstmt.setInt(1, id);
              pstmt.executeUpdate();
          }
      
          try (final PreparedStatement pstmt = conn.prepareStatement(String.format("SELECT VALUE FROM %s WHERE ID = ? FOR UPDATE", tableName))) {
              pstmt.setInt(1, id);
              try (final ResultSet rset = pstmt.executeQuery()) {
                  while (rset.next()) {
                      final Blob blob = rset.getBlob(1);
                      try (final OutputStream out = new BufferedOutputStream(blob.setBinaryStream(1L))) {
                          out.write(value);
                      }
                  }
              }
          }
      }
      
    3. For CLOBs and NCLOBs, you can additionally use PreparedStatement.setString() and setNString(), respectively.

    0 讨论(0)
提交回复
热议问题