Blob是指二進位大對象也就是英文Binary Large Object的所寫,而Clob是指大字元對象也就是英文Character Large Object的所寫。由此可見這輛個類型都是用來儲存大量資料而設計的,其中BLOB是用來儲存大量位元據的;CLOB用來儲存大量文本資料。
那麼有人肯定要問既然已經有VARCHAR和VARBINARY兩中類型,為什麼還要再使用另外的兩種類型呢?其實問題很簡單,VARCHAR和VARBINARY兩種類型是有自己的局限性的。首先說這兩種類型的長度還是有限的不可以超過一定的限額,以VARCHAR再ORA中為例長度不可以超過4000;那麼有人又要問了,LONGVARCHAR類型作為資料庫中的一種儲存字元的類型可以滿足要求,儲存很長的字元,那為什麼非要出現CLOB類型呢?其實如果你用過LONGVARCHAR類型就不難發現,該類型的一個重要缺陷就是不可以使用LIKE這樣的條件檢索。(稍候將介紹在CLOB中如何?類似LIKE的模糊尋找)另外除了上述的問題外,還又一個問題,就是在資料庫中VARCHAR和VARBINARY的存取是將全部內容從全部讀取或寫入,對於100K或者說更大資料來說這樣的讀寫方式,遠不如用流進行讀寫來得更現實一些。
在JDBC中有兩個介面對應資料庫中的BLOB和CLOB類型,java.sql.Blob和java.sql.Clob。和你平常使用資料庫一樣你可以直接通過ResultSet.getBlob()方法來擷取該介面的對象。與平時的尋找唯一不同的是得到Blob或Clob的對象後,我們並沒有得到任何資料,但是我們可以這兩個介面中的方法得到資料。
例如:
Blob b=resultSet.getBlob(1);
InputStream bin=b.getBinaryStryeam();
Clob c=resultSet.getClob(2);
Reader cReader=c.getCharacterStream():
關於Clob類型的讀取可以使用更直接的方法,就是直接通過ResultSet.getCharacterStream();方法獲得字元流,但該方法並不安全,所以建議還是使用上面例子的方法擷取Reader。
另外還有一種擷取方法,不使用資料流,而是使用資料區塊。
例如
Blob b=resultSet.getBlob(1);
byte data=b.getByte(0,b.length());
Clob c=resultSet.getClob(2);
String str=c.getSubString(0,c.length()):
在這裡我要說明一下,這個方法其實並不安全,如果你很細心的話,那很容易就能發現getByte()和getSubString()兩個方法中的第二個參數都是int類型的,而BLOB和CLOB是用來儲存大量資料的。而且Bolb.length()和Clob.length()的傳回值都是long類型的,所以很不安全。這裡不建議使用。但為什麼要在這裡提到這個方法呢?稍候告訴你答案,這裡你需要記住使用資料區塊是一種方法。
在儲存的時候也同樣的在PreparedStatement和CallableStatememt中,以參數的形式使用setBlob()和setClob方法把Blob和Clob對象作為參數傳遞給SQL。這聽起來似乎很簡單對吧,但是並非我們想象的這樣,很不幸由於這兩個類型的特殊,JDBC並沒有提供獨立於資料庫驅動的Blob和Clob建立對象。因此需要自己編寫與驅動有關的代碼,但這樣又牽掣到移植性。怎樣才是解決辦法呢?這就要用到前面說過的思想了使用資料區塊進行寫操作。同樣用PreparedStatement和CallableStatememt類,但參數的設定可以換為setAsciiStream、setBinaryStream、setCharacterStream、setObject(當然前3個同樣存在長度的問題)
下面給大家個例子以方便大家理解
public void insertFile(File f) throws Exception{
FileInputStream fis=new FileInputStream(f,Connection conn);
byte[] buffer=new byte[1024];
data=null;
int sept=0;int len=0;
while((sept=fis.read(buffer))!=-1){
if(data==null){
len=sept;
data=buffer;
}else{
byte[] temp;
int tempLength;
tempLength=len+sept;
temp=new byte[tempLength];
System.arraycopy(data,0,temp,0,len);
System.arraycopy(buffer,0,temp,len,sept);
data=temp;
len=tempLength;
}
if(len!=data.length()){
byte temp=new byte[len];
System.arraycopy(data,0,temp,0,len);
data=temp;
}
}
String sql="insert into fileData (filename,blobData) value(?,?)";
PreparedStatement ps=conn.prepareStatement(sql);
ps.setString(1,f.getName());
ps.setObject(2,data);
ps.executeUpdate();
}
最後由於剛剛說過Clob類型讀取字元的長度問題,這裡再給大家一段代碼,希望對你有協助
public static String getClobString(ResultSet rs, int col) {
try {
Clob c=resultSet.getClob(2);
Reader reader=c.getCharacterStream():
if (reader == null) {
return null;
}
StringBuffer sb = new StringBuffer();
char[] charbuf = new char[4096];
for (int i = reader.read(charbuf); i > 0; i = reader.read(charbuf)) {
sb.append(charbuf, 0, i);
}
return sb.toString();
} catch (Exception e) {
return "";
}
}
另外似乎前面還提到過LIKE檢索的問題。LONGVARCHAR類型中不可以用LIKE尋找(至少ORA中不可以使用,其他的資料庫我沒有試過),在ORA中我們可以使用這樣一個函數dbms_lob.instr來代替LIKE來個例子吧
select docid,dat0 from text where dbms_lob.instr(dat0,'魏',1,1)>0
在text表中有兩個欄位docid用來放文檔編號dat0為clob類型存放文章內容;這句話的意思就是檢索第一條dat0中出現第一次"魏"字的資料。聽起來這個檢索的資料有點象google的“手氣不錯”