Wie Sie schreiben / aktualisieren von Oracle-blob in eine zuverlässige Möglichkeit?
Ich versuche zu schreiben und Aktualisierung eines pdf-Dokuments in einem blob-Spalte, aber ich bin nur in der Lage, zur Aktualisierung der blob nur schreiben mehr Daten als die vorherigen gespeicherten Daten.
Wenn ich versuche zu aktualisieren, die blob-Spalte mit einem kleineren Dokument-Daten bekomme ich nur eine beschädigte pdf-Datei.
Zuerst der blob-Spalte initialisiert wurde mit empty_blob () - Funktion. Ich habe die Beispiel-Java-Klasse unten, um zu testen, dieses Verhalten. Ich es das erste mal mit 'true' als ersten parameter der main Methode so in der ersten Reihe dort gespeichert ein Dokument über 31kB und in der zweiten Zeile gibt es ein Dokument von 278kB.
Dann habe ich es mit 'false' als parameter, auf diese Weise die zwei Zeilen aktualisiert werden soll der Austausch der Dokumente. Das Ergebnis ist, dass ich eine richtige Ergebnis nur, wenn ich Schreibe mehr Daten als die bereits vorhandenen.
Wie ist es möglich, zu schreiben, eine Methode, die schreibt und updates ein blob in einer zuverlässigen Weise, ohne worring über binäre Daten Größe?
import static org.apache.commons.io.IOUtils.copy;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import oracle.jdbc.OracleDriver;
import oracle.jdbc.OracleResultSet;
import oracle.sql.BLOB;
import org.apache.commons.lang.ArrayUtils;
/**
* Prerequisites:
* 1) a table named 'x' must exists [create table x (i number, j blob);]
* 2) that table should have two columns [insert into x (i, j) values (1, empty_blob()); insert into x (i, j) values (2, empty_blob()); commit;]
* 3) download lsp.pdf from http://www.objectmentor.com/resources/articles/lsp.pdf
* 4) download dotguide.pdf from http://www.graphviz.org/Documentation/dotguide.pdf
*/
public class UpdateBlob {
public static void main(String[] args) throws Exception {
processFiles(new String[]{"lsp.pdf", "dotguide.pdf"}, Boolean.valueOf(args[0]));
}
public static void processFiles(String [] fileNames, boolean forward) throws Exception {
if(!forward){
ArrayUtils.reverse(a);
}
int idx = 1;
for(String fname : fileNames){
insert(idx++, fname);
}
}
private static void insert(int idx, String fname) throws Exception{
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
DriverManager.registerDriver(new OracleDriver());
conn = DriverManager.getConnection("jdbc:oracle:thin:@"+db+":"+port+":"+sid, user, pwd);
ps = conn.prepareStatement("select j from x where i = ? for update");
ps.setLong(1, idx);
rs = ps.executeQuery();
if (rs.next()) {
FileInputStream instream = new FileInputStream(fname);
BLOB blob = ((OracleResultSet)rs).getBLOB(1);
OutputStream outstream = blob.setBinaryStream(1L);
copy(instream, outstream);
instream.close();
outstream.close();
}
rs.close();
ps.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
throw new Exception(e);
}
}
}
Oracle-version: 11.1.0.7.0 - 64bit
Ich habe sogar versucht die standard-JDBC-API ohne Verwendung von Oracle-spezifische (wie im Beispiel oben), ohne Erfolg.
copy
Methode definiert? Meine Vermutung ist, dass die copy
Methode ist nicht zu tun, was Sie erwarten und ist nur Austausch der ersten N bytes, wenn die neuen Daten kleiner als die alten Daten.Btw: Sie sollten nicht öffnen Sie eine neue Verbindung für jeden Aufruf der Funktion. Das ist, tot zu sein langsam.
copy
Methode ist definiert in den org.apache.Unterhaus.io.IOUtils Klasse. Es gibt einen statischen import am Anfang des Codes. Statische Importe macht das weniger lesbar, aber ich denke, dass in einigen Fällen ist es bequem, Sie zu benutzen.Der code oben ist nur eine wirklich schnelle POC. Ich benutze immer ein connection-pool zu verwalten, db-Verbindung.
InformationsquelleAutor alexyz78 | 2011-12-01
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es ist viel einfacher:
Es funktioniert auf die gleiche, wenn mithilfe einer INSERT-Anweisung. Keine Notwendigkeit für
empty_blob()
und eine zweite update-Anweisung.setBinaryStream
's Signatur ist(int parameterIndex, InputStream x, int length)
).Was ist, wenn es ist ein java-Objekt und nicht eine Datei?
Hari: verwenden Sie einen ObjectInputStream oder einen ByteArrayInputStream
Ich bin mit dem gleichen problem und versuchen, um diese Lösung zu implementieren. Was soll ich den PK-Wert? Ist es abhängig von der Datenbank?
zu wissen, was der PK-Wert ist. Dies könnte eine Folge Wert, oder eine GUID oder etwas anderes. Sie sind der nur derjenige, der diese Frage beantworten kann,.
InformationsquelleAutor a_horse_with_no_name
Neben a_horse_with_no_name's Antwort (die stützt sich auf PreparedStatement.setBinaryStream(...) API), es sind mindestens zwei weitere Optionen für BLOBs, und 3 weitere für CLOBs und NCLOBs:
Explizit erstellen Sie ein LOB, zu schreiben, und verwenden Sie
PreparedStatement.setBlob(int, Blob)
:Update ein leeres LOB (eingefügt über
DBMS_LOB.EMPTY_BLOB()
oderDBMS_LOB.EMPTY_CLOB()
) überSELECT ... FOR UPDATE
. Dies ist Oracle-spezifisch und erfordert zwei Anweisungen ausgeführt statt. Darüber hinaus dies ist, was Sie versuchen zu erreichen, in Erster Linie:Für CLOBs und NCLOBs, kannst du zusätzlich
PreparedStatement.setString()
undsetNString()
bzw.InformationsquelleAutor Bass
FWIW, für etwas, das passt in Erinnerung, fand ich, ich könnte einfach gehen in ein byte-array als die vorbereitete Anweisung parameter, anstatt durch die "stream" strenge Moral (oder noch schlimmer Oracle-spezifischen/vorgeschlagenen Dinge)
Mithilfe einer Feder "JDBC-template" wrapper - (org.springframework.jdbc.core.JdbcTemplate), um den Inhalt einer "großen" (oder auch nicht) string in eine BLOB-Spalte der code ist so etwas wie die folgenden:
Es gibt keinen Schritt 2.
InformationsquelleAutor Roboprog