我正在尝试在blob列中编写和更新pdf文档,但是我只能够更新blob,仅写入比先前存储的数据更多的数据。如果尝试使用较小的文档数据更新blob列,则只会得到损坏的pdf。
首先,blob列已使用empty_blob()函数进行了初始化。我在下面编写了示例Java类来测试此行为。我第一次使用“ true”作为 main 方法的第一个参数运行它,因此在第一行中存储了大约31kB的文档,在第二行中存储了278kB的文档。然后,我以’false’作为参数运行它,通过这种方式应该交换两行以交换文档。结果是,仅当我写入的数据多于现有数据时,我才能获得正确的结果。
如何编写一种以可靠的方式写入和更新Blob而不担心二进制数据大小的方法?
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版本:11.1.0.7.0-64位
我什至没有使用Oracle的专用JDBC API(例如上例)就尝试了标准的JDBC API,但没有成功。
这要容易得多:
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();
使用INSERT语句时,其工作原理相同。不需要empty_blob()第二条更新语句。
empty_blob()