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