Oracle 的Blob
Oracle的Lobs的流處理方式與Long等對象的Stream方式不一樣,沒有Long的諸多限制;只要保持連接,就能通過blob對象正確讀取對象。
有兩種方式可以讀取Blob:
1.直接使用ps.getBinaryStream()的方法得到流對象
2.使用getBlob得到blob,然后通過blob的方法提供的getBinaryStream(),getBytes() 訪問blob的數據。
這兩種方法都可以在rs.close之后正確獲取數據。(在spring 的JdbcTemplet環境下,該rs理論上被JdbcTemplet自動關閉;從數據庫連接來看,連接也正確關閉了)。
使用Blob的好處是,按需獲取Blob對象。而且可以多次通過blob.getBinaryStream得到對象。且Blob返回的對象可以使用mark/reset方法反復訪問。且連接狀態正常。
使用blob得到InputStream,可以調用close()接口,也可以不調用該接口,
tb在連接關閉時將自動關閉該連接。最好調用close()釋放資源。
c3p0的setBlob(pos,InputStream)接口不能正常工作。
寫入或更新Blob時,可以使用ps.setBinaryStream();調用此接口后,in對象到文件尾(在把stream寫入blob后,不能要再調用in.close()關閉文件,否則報錯)。
也可以使用setBlob(pos,Blob)方法來寫入或更新Blob字段;但是注意的是,無論是以blob還是blob.getBinaryStream的方式,都不能自己更新自己,否則死鎖。
使用spring讀取blob的示例程序:
String sql = "select photo from my_photoes where id='test2' and photo is not null and rownum<2 ";
BLOB blob= (BLOB) simpleDao.queryForObject(sql,Blob.class);
InputStream in = blob.getBinaryStream();
String filename = "./test/dao/pic" + 1+ ".gif";
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(filename));
/* 需oracle的BLOB支持。效率可能會高些,但是空間上會有些浪費
byte[] b = new byte[blob.getBufferSize()];
//blob必須為oracle.sql.BLOB時才可調getBufferSize方法; 與java.sql.Blob區別。
System.out.println("bufferSize="+b.length);
//32k左右,用這種方式讀取文件會有一點空間的浪費。
int len=-1;
while ((len = in.read(b)) != -1) {
out.write(b);
}
*/
/* 純jdbc方法:
nt b;
while ((b = in.read()) != -1) {
out.write(b);
}
*/
in.close();
out.close();
BLOB處理遇到的問題:
1.用spring的模板類來處理blob時,遇到大文件時,流會異常關閉。解決辦法,使用oracle的本地連接來獲取blob流,如下:
public boolean queryForBlobStream(String sql,OutputStream fout)
{
boolean flag=true;
try {
Connection conn = DataSourceUtils.getConnection(getJdbcTemplate().getDataSource());
conn.setAutoCommit(false); //此部分ms能提高性能
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
if (rs.next()) {
java.sql.Blob blob = rs.getBlob(1);
InputStream ins = blob.getBinaryStream();
//輸出到文件
//下面將BLOB數據寫入文件
byte[] b = new byte[1024];
int len = 0;
while ((len = ins.read(b)) != -1) {
fout.write(b, 0, len);
}
//依次關閉
fout.close();
ins.close();
}
conn.commit();
rs.close(); //maybe not nessesary
st.close(); //maybe not nessesary
conn.close();
} catch (IOException ex) {
flag=false;
} catch (SQLException ex) {
flag=false;
}
return flag;
}
2.如果把blob對象放到記錄的字段中,在web開發中,通過blob.getBinaryStream()只能獲得一次blob流,第二次調用同一對象的blob流會得到null流。
且在這種方式下,不能使用in.close()關閉流。