When I search the web for inserting BLOBs into Oracle database with jdbc thin driver, most of the webpages suggest a 3-step approach:
empty_blob()
value.for update
.This works fine for me, here is an example:
Connection oracleConnection = ...
byte[] testArray = ...
PreparedStatement ps = oracleConnection.prepareStatement(
"insert into test (id, blobfield) values(?, empty_blob())");
ps.setInt(1, 100);
ps.executeUpdate();
ps.close();
ps = oracleConnection.prepareStatement(
"select blobfield from test where id = ? for update");
ps.setInt(1, 100);
OracleResultSet rs = (OracleResultSet) ps.executeQuery();
if (rs.next()) {
BLOB blob = (BLOB) rs.getBLOB(1);
OutputStream outputStream = blob.setBinaryStream(0L);
InputStream inputStream = new ByteArrayInputStream(testArray);
byte[] buffer = new byte[blob.getBufferSize()];
int byteread = 0;
while ((byteread = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, byteread);
}
outputStream.close();
inputStream.close();
}
There are some webpages where the authors suggest using a simpler 1-step solution. Previous example with this solution:
Connection oracleConnection = ...
byte[] testArray = ...
PreparedStatement ps = oracleConnection.prepareStatement(
"insert into test(id, blobfield) values(?, ?)");
BLOB blob = BLOB.createTemporary(oracleConnection, false, BLOB.DURATION_SESSION);
OutputStream outputStream = blob.setBinaryStream(0L);
InputStream inputStream = new ByteArrayInputStream(testArray);
byte[] buffer = new byte[blob.getBufferSize()];
int byteread = 0;
while ((byteread = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, byteread);
}
outputStream.close();
inputStream.close();
ps.setInt(1, 100);
ps.setBlob(2, blob);
ps.executeUpdate();
ps.close();
The second code is much more easier, so my question is: What is the point of first (popular) solution? Is there (was there) some kind of constraint for the second solution (Oracle server version number, jdbc driver version, size of the blob,...)? Is the first solution better (speed, memory consumption,...)? Any reasons for not using the simpler second approach?
The exact same question applies for CLOB fields.
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 + " = ? "