JDBC高級應用(二)
本來想繼續談JDBC的高級連結方式,事務模式.但發現關于大對象存儲有很多人在問,所以
先來插入一節關于大對象存儲的內容,然后再接著原來的思路寫下去.
JDBC的大對象存儲聽起來復雜,其實如果你明白了原理以后,就非常簡單,網上有關這方面的
教材很少,而SUN的文檔中,我從1.2開始看到一在仍然是錯誤的,不知道寫文檔的人長腦子沒
有,就那幾行代碼你試試不就知道了,這么多次重抄下來還是錯誤的.
大對象分類:一般來說,大對象分為:大的文本對象,比如一個很長的文本(請你要注意什么是
文本文件,什么是二進制文件)文件,或者是你定義的一個長字符串,比如你定義了:
String s = "我們要去吃飯了......................然后睡覺!";
從吃飯到睡覺中間省略了實際的10000000000000字,雖然你不會真的定義這么稱的String,但
有時會從什么地方得到這樣的String,要寫到數據庫中.
另一種就是大的二進制對象,象執行文件,圖象文件等,注意,word,excel,ppt這些"帶格式"的文
檔都應該以二進制對象存儲.
一般來說,數據庫如果支持大對象存儲,會有這幾種類型的SQL數據類型:
BLOB,CLOCB,NLOB,也有的數據數只有一種BLOB,基本上是這樣的:BLOB用來存放二進制文件,而
CLOB用來存放文本文件,NLOB是對多字節文本文件支持.假如你的文本文件是純英文的,放在
BLOB中當然可以,也就是說它是以byte格式存儲的,而多字節是以CHAR格式存儲的.
同樣對于這幾種類型的文檔,有幾種相對應的存取方式:
setter:
利用PreparedStatement的setXXX方法,
setAsciiStream()方法用于寫入一般的文本流.setBinaryStream()方法用于寫入二進制流
而setUnicodeStream()用于寫好UNICODE編碼的文本,與此相對應的ResultSet中三個getter方法
用于取回:getAsciiStream(),getBinaryStream(),getBinaryStream().
對于文件本身,要把它作為一個流,只要new InputStream(new FileInputStream("文件路徑"))
就可以了,但對于大的String對象,你不會寫入文件再轉換成輸入流吧?
new StringBufferInputStream(String s),記住了.
JDBC2以后提供了java.sql.BLOB對象,我不建議大家使用它,一是很麻類,二是容易出錯,要先插
入一個空的BLOB對象,然后再填充它,實在沒有必要,直接setXXX就行了,我試過,至少mysql,
oracle,sql server是可以直接set的.
好了,我們先看一個例子如何寫入文件到數據庫:
數據結構:
create table test(
name varchar(200),
content BLOB
);
File f = new File("a.exe");//先生成File對象是為了取得流的長度.FileInputStram可以直接
//傳入文件路徑
InputStream in = new InputStream(new FileInputStream(f));
PreparedStatement ps = conn.prepareStatement("insert into test (?,?)");
ps.setString(1,"a.exe");
ps.setBinaryStream(2,in,(int)f.length());
ps.executeUpdate();
f的長度一定要做從long到int的轉換,SUN的文檔中好幾版都沒有改過來.就這么簡單,當然,不同的
數據庫存本身要設置它允許的最大長度,MYSQL默認只能傳1M的文件,要修改參數原能存更大的文件.
如果要從數庫中取得文件:
PreparedStatement ps = conn.prepareStatement("select * from test where name=?");
ps.setString(1,"a.exe");
ResultSet rs = ps.executeQuery();
if(rs.next()){
InputStream in = rs.getBinaryStream("content");
}
得到in對象后,你可以進行任何處理,寫向文件和寫向頁面只是out對象不同而已:
寫向文件:
DateOutputStream out = new DateOutputStream(new FileOutputStream("b.exe"));
寫向頁面:
response.reset();
response.setContType("類型");
ServletOutputSreamt out = response.getOutputSream();
得到out對象后,就可以輸出了:
byte[] buf = new byte[1024];
int len = 0;
while((len = in.read(buf)) >0)
out.write(buf,0,len);
in.close();
out.close();
對于向頁面輸入,要設置什么樣的ContType,要看你想如何輸出,如果你想讓對方下載,就設為
"application/octet-stream",這樣即使是文本,圖象都會下載而不會在瀏覽器中打開.如果你要想
在瀏覽器中打開,就要設置相應的類型,還要在容器的配置文件中設置支持這種文檔類型的輸出,但
對于很多格式的文件,到底要輸出什么類型,其實就是HTTP的MIME集,比如圖片:image/gif,當然你如
果你的文件擴展名(ext)不確定,你也不要用if(ext.equals("gif"))......這樣來判斷,我教你一個
技巧,我之所以說是技巧,是我沒有在別的地方發現有人用這種方法,對我來說我是絕對不會把別人的
方法拿來說是我的技巧的:
構造一個file類型的URL,我們知道URL目前JAVA可以支持HTTP,FTP,MAILTO,FILE,LDAP等,從FILE類型
的URL就可以得到它的MIME:
URL u = new URL("file://a.exe");
String mime = u.openConnection().getContentType();
這樣你就可以直接response.setContType(mime);而不用一個一個類型判斷了.
好了,大對象存儲就說到這兒,不同的數據仍然和些特殊的規定,不在此一一列舉了.