#

Blobs with JDBC

Gelegentlich kommt es vor, dass man Blobs (Binary Large OBjects) in der Datenbank speichern muss. Je nach Datenbank und Version muss man aber ein gezieltes Statement benutzen, damit das alles auch klappt.

Eigentlich sollte es wie folgt klappen:

byte [] data = getMyBinaryData();
stmt = conn.prepareStatement("INSERT INTO data (id, content) VALUES (?,?)");
stmt.setLong(1, myId);
stmt.setBytes(2, data);
stmt.executeUpdate();

Das geht nur solange gut, wie die Datenmenge klein ist (meist kleiner als der von der Datenbank benutzte Übertragungspuffer). Aber dann auch nicht immer.

Ein alternativer Ansatz ist es, das Ganze über zwei Statements zu machen: Ein Insert mit einem leeren Blob und anschließend ein Select Update um das Feld zu beschrieben. Dies hat aber nicht immer geklappt. (Ich weiß immernoch nicht wieso es manchmal ging, manchmal aber auch nicht.)

byte [] data = getMyBinaryData();
ResultSet rs = null;
OutputStream out = null;
stmta = conn.prepareStatement("INSERT INTO data (id, content) VALUES (?, EMPTY_BLOB())");
stmta.setLong(1, myId);
stmta.executeUpdate();
 
stmtb = conn.prepareStatement("SELECT content FROM data WHERE id = ? FOR UPDATE");
stmtb.setLong(1, myId);
rs = stmtb.executeQuery();
if (rs.next()) {
  // casting jdbc blob to oracle blob 
  Blob blob = rs.getBlob(1);
  out = ((BLOB) blob).setBinaryStream(0L);
  out.write(data, 0, data.length);
  out.flush();
  out.close();
}

Meines erachtens sehr umständlich und, wie bereits gesagt, gelegentlich fehleranfällig. Anscheinend hat dies ebenfalls mit der größe des Übertragungspuffers zu tun.
Auch muss man hierbei mehr herumfummeln, wenn die benutze id erst durch das Insert Statement generiert wurde.

Nun, aller guter Dinge sind drei. Entsprechend habe ich etwas im Netz gefunden, dass zumindest mit Oracle ojdbc14, funktioniert:

stmt = conn.prepareStatement("INSERT INTO data (id,content) VALUES (?,?)");
stmt.setLong(1, myId);
stmt.setBinaryStream(2, new ByteArrayInputStream(data), data.length);
stmt.execute();

So sollte es sein. Warum die Methode stmt.setBytes() nicht automatisch intern die setBinaryStream benutzt, weiss ich leider nicht.
In dem Beitrag, der mir diese Lösung präsentierte, wird erwähnt, dass die setBinaryStream mit InputStream variante automatisch die vom JDBC Treiber benutzte Puffergröße perfekt unterstützt, da in diesem Fall der JDBC-Treiber selber die entsprechende Menge an Bytes aus dem Stream liest.

Tags:, , , ,

Leave a Reply »»

Note: All comments are manually approved to avoid spam. So if your comment doesn't appear immediately, that's ok. Have patience, it can take some days until I have the time to approve my comments.