Overcomplicated oracle jdbc BLOB handling

前端 未结 9 974
予麋鹿
予麋鹿 2020-12-04 18:20

When I search the web for inserting BLOBs into Oracle database with jdbc thin driver, most of the webpages suggest a 3-step approach:

  1. insert empty_blob()
相关标签:
9条回答
  • 2020-12-04 18:22

    The update approach you mention in the first case can be rewritten using pure JDBC code and thus reduce your dependency on Oracle-specific classes. This could be helpful if your app needs to be database agnostic.

    public static void updateBlobColumn(Connection con, String table, String blobColumn, byte[] inputBytes, String idColumn, Long id) throws SQLException {
      PreparedStatement pStmt = null;
      ResultSet rs = null;
      try {
        String sql = 
          " SELECT " + blobColumn + 
          " FROM " + table + 
          " WHERE " + idColumn + " = ? " +
          " FOR UPDATE";
        pStmt = con.prepareStatement(sql, 
          ResultSet.TYPE_FORWARD_ONLY, 
          ResultSet.CONCUR_UPDATABLE);
        pStmt.setLong(1, id);
        rs = pStmt.executeQuery();
        if (rs.next()) {
          Blob blob = rs.getBlob(blobColumn);
          blob.truncate(0);
          blob.setBytes(1, inputBytes);
          rs.updateBlob(blobColumn, blob);
          rs.updateRow();
        }
      }
      finally {
        if(rs != null) rs.close();
        if(pStmt != null) pStmt.close();
      }
    }
    

    For MSSQL I understand that the locking syntax is different:

    String sql = 
      " SELECT " + blobColumn + 
      " FROM " + table + " WITH (rowlock, updlock) " + 
      " WHERE " + idColumn + " = ? "
    
    0 讨论(0)
  • 2020-12-04 18:24

    Provided the CLOB data is small enough to fit in your memory without blowing up, you can just create a prepared statement and simply call

    ps.setString(1, yourString);
    

    There may be other size limitations, but it seems to work for the sizes we're dealing with (500kB max).

    0 讨论(0)
  • 2020-12-04 18:26

    One interesting thing with JDBC is you can upgrade rather aggressively to the latest drivers and work with JDBC 4.0 features. The oracle JDBC drivers will work with older database versions, so you can use an 11g branded JDBC driver against a 10g database. The Oracle database 11g JDBC comes in two flavors: ojdbc5.jar for Java 5 (i.e., JDK 1.5) and ojdbc6.jar for Java 6 (i.e., JDK 1.6). The ojdbc6.jar supports the new JDBC 4.0 specification.

    With the newer drivers/jdbc 4.0 you can create Blobs and Clobs off the connection object:

    Blob aBlob = con.createBlob();
    int numWritten = aBlob.setBytes(1, val);
    
    0 讨论(0)
  • 2020-12-04 18:29

    This statement :

    blob.setBytes(1, inputBytes);
    

    is giving issues when I use oracle thin client ojdbc14.jar, "Unsupported Features"

    So, I had to work around by :

    rset.next();
    Blob bobj = rset.getBlob(1);
    BLOB object = (BLOB) bobj;
    int chunkSize = object.getChunkSize();
    byte[] binaryBuffer = new byte[chunkSize];
    int position = 1;
    int bytesRead = 0;
    int bytesWritten = 0, totbytesRead = 0, totbytesWritten = 0;
    InputStream is = fileItem.getInputStream();
    while ((bytesRead = is.read(binaryBuffer)) != -1) {
    bytesWritten = object.putBytes(position, binaryBuffer, bytesRead);
    position += bytesRead;
    totbytesRead += bytesRead;
    totbytesWritten += bytesWritten;
    is.close();
    
    0 讨论(0)
  • 2020-12-04 18:29

    If size of inserting BLOB is greater than blob.getBufferSize(), transaction is commited as soon as first chunk is written to db as default value of autoCommit property of jdbc connection is true and further chunks writes fail as db treats them as new transactions. It is suggested as follows:
    a) Set jdbc connection autoCommit property to false.

    conn.setAutoCommit(false);
    

    b) Explicitely commit the transaction after uploading the whole BLOB.

    while ((bytesRead = messageInputStream.read(buffer)) != -1) {
         cumBytes += bytesRead;
         blobOutputStream.write(buffer, 0, bytesRead);
        }
    conn.commit();
    
    0 讨论(0)
  • 2020-12-04 18:35

    Some watchouts found for the second solution

    I am using ojdbc6.jar - the latest release and for the statement from 'the second solution':

    BLOB blob = BLOB.createTemporary(oracleConnection, false, BLOB.DURATION_SESSION);
    

    I have to release blob after the statement is completed - or otherwise blob is closed when session is closed (which can take long time with connection pooling).

    blob.freeTemporary();
    

    Otherwise you can see locked resources:

    select * from v$temporary_lobs
    

    Another problem with temporary BLOBs is the need to allocate temporary tablespace: as per documentation http://docs.oracle.com/cd/E11882_01/appdev.112/e18294.pdf

    Managing Temporary Tablespace for Temporary LOBs Temporary tablespace is used to store temporary LOB data

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