在Oracle中,LOB(Large Object,大型對(duì)象)類型的字段現(xiàn)在用得越來越多了。因?yàn)檫@種類型的字段,容量大(最多能容納4GB的數(shù)據(jù)),且一個(gè)表中可以有多個(gè)這種類型的字段,很靈活,適用于數(shù)據(jù)量非常大的業(yè)務(wù)領(lǐng)域(如圖象、檔案等)。而LONG、LONG RAW等類型的字段,雖然存儲(chǔ)容量也不小(可達(dá)2GB),但由于一個(gè)表中只能有一個(gè)這樣類型的字段的限制,現(xiàn)在已很少使用了。
LOB類型分為BLOB和CLOB兩種:BLOB即二進(jìn)制大型對(duì)象(Binary Large Object),適用于存貯非文本的字節(jié)流數(shù)據(jù)(如程序、圖象、影音等)。而CLOB,即字符型大型對(duì)象(Character Large Object),則與字符集相關(guān),適于存貯文本型的數(shù)據(jù)(如歷史檔案、大部頭著作等)。
下面以程序?qū)嵗f明通過JDBC操縱Oracle數(shù)據(jù)庫(kù)LOB類型字段的幾種情況。
先建立如下兩個(gè)測(cè)試用的數(shù)據(jù)庫(kù)表,Power Designer PD模型如下:

建表SQL語(yǔ)句為:
CREATE TABLE TEST_CLOB ( ID NUMBER(3), CLOBCOL CLOB)
CREATE TABLE TEST_BLOB ( ID NUMBER(3), BLOBCOL BLOB)
一、 CLOB對(duì)象的存取
1、往數(shù)據(jù)庫(kù)中插入一個(gè)新的CLOB對(duì)象
public static void clobInsert(String infile) throws Exception
{
/* 設(shè)定不自動(dòng)提交 */
boolean defaultCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
try {
/* 插入一個(gè)空的CLOB對(duì)象 */
stmt.executeUpdate("INSERT INTO TEST_CLOB valueS ('111', EMPTY_CLOB())");
/* 查詢此CLOB對(duì)象并鎖定 */
ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='111' FOR UPDATE");
while (rs.next()) {
/* 取出此CLOB對(duì)象 */
oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");
/* 向CLOB對(duì)象中寫入數(shù)據(jù) */
BufferedWriter out = new BufferedWriter(clob.getCharacterOutputStream());
BufferedReader in = new BufferedReader(new FileReader(infile));
int c;
while ((c=in.read())!=-1) {
out.write(c);
}
in.close();
out.close();
}
/* 正式提交 */
conn.commit();
} catch (Exception ex) {
/* 出錯(cuò)回滾 */
conn.rollback();
throw ex;
}
/* 恢復(fù)原提交狀態(tài) */
conn.setAutoCommit(defaultCommit);
}
2、修改CLOB對(duì)象(是在原CLOB對(duì)象基礎(chǔ)上進(jìn)行覆蓋式的修改)
public static void clobModify(String infile) throws Exception
{
/* 設(shè)定不自動(dòng)提交 */
boolean defaultCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
try {
/* 查詢CLOB對(duì)象并鎖定 */
ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='111' FOR UPDATE");
while (rs.next()) {
/* 獲取此CLOB對(duì)象 */
oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");
/* 進(jìn)行覆蓋式修改 */
BufferedWriter out = new BufferedWriter(clob.getCharacterOutputStream());
BufferedReader in = new BufferedReader(new FileReader(infile));
int c;
while ((c=in.read())!=-1) {
out.write(c);
}
in.close();
out.close();
}
/* 正式提交 */
conn.commit();
} catch (Exception ex) {
/* 出錯(cuò)回滾 */
conn.rollback();
throw ex;
}
/* 恢復(fù)原提交狀態(tài) */
conn.setAutoCommit(defaultCommit);
}
3、替換CLOB對(duì)象(將原CLOB對(duì)象清除,換成一個(gè)全新的CLOB對(duì)象)
public static void clobReplace(String infile) throws Exception
{
/* 設(shè)定不自動(dòng)提交 */
boolean defaultCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
try {
/* 清空原CLOB對(duì)象 */
stmt.executeUpdate("UPDATE TEST_CLOB SET CLOBCOL=EMPTY_CLOB() WHERE ID='111'");
/* 查詢CLOB對(duì)象并鎖定 */
ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='111' FOR UPDATE");
while (rs.next()) {
/* 獲取此CLOB對(duì)象 */
oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");
/* 更新數(shù)據(jù) */
BufferedWriter out = new BufferedWriter(clob.getCharacterOutputStream());
BufferedReader in = new BufferedReader(new FileReader(infile));
int c;
while ((c=in.read())!=-1) {
out.write(c);
}
in.close();
out.close();
}
/* 正式提交 */
conn.commit();
} catch (Exception ex) {
/* 出錯(cuò)回滾 */
conn.rollback();
throw ex;
}
/* 恢復(fù)原提交狀態(tài) */
conn.setAutoCommit(defaultCommit);
}
4、CLOB對(duì)象讀取
public static void clobRead(String outfile) throws Exception
{
/* 設(shè)定不自動(dòng)提交 */
boolean defaultCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
try {
/* 查詢CLOB對(duì)象 */
ResultSet rs = stmt.executeQuery("SELECT * FROM TEST_CLOB WHERE ID='111'");
while (rs.next()) {
/* 獲取CLOB對(duì)象 */
oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");
/* 以字符形式輸出 */
BufferedReader in = new BufferedReader(clob.getCharacterStream());
BufferedWriter out = new BufferedWriter(new FileWriter(outfile));
int c;
while ((c=in.read())!=-1) {
out.write(c);
}
out.close();
in.close();
}
} catch (Exception ex) {
conn.rollback();
throw ex;
}
/* 恢復(fù)原提交狀態(tài) */
conn.setAutoCommit(defaultCommit);
}
二、 BLOB對(duì)象的存取
1、 向數(shù)據(jù)庫(kù)中插入一個(gè)新的BLOB對(duì)象
public static void blobInsert(String infile) throws Exception
{
/* 設(shè)定不自動(dòng)提交 */
boolean defaultCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
try {
/* 插入一個(gè)空的BLOB對(duì)象 */
stmt.executeUpdate("INSERT INTO TEST_BLOB valueS ('222', EMPTY_BLOB())");
/* 查詢此BLOB對(duì)象并鎖定 */
ResultSet rs = stmt.executeQuery("SELECT BLOBCOL FROM TEST_BLOB WHERE ID='222' FOR UPDATE");
while (rs.next()) {
/* 取出此BLOB對(duì)象 */
oracle.sql.BLOB blob = (oracle.sql.BLOB)rs.getBlob("BLOBCOL");
/* 向BLOB對(duì)象中寫入數(shù)據(jù) */
BufferedOutputStream out = new BufferedOutputStream(blob.getBinaryOutputStream());
BufferedInputStream in = new BufferedInputStream(new FileInputStream(infile));
int c;
while ((c=in.read())!=-1) {
out.write(c);
}
in.close();
out.close();
}
/* 正式提交 */
conn.commit();
} catch (Exception ex) {
/* 出錯(cuò)回滾 */
conn.rollback();
throw ex;
}
/* 恢復(fù)原提交狀態(tài) */
conn.setAutoCommit(defaultCommit);
}
2、修改BLOB對(duì)象(是在原BLOB對(duì)象基礎(chǔ)上進(jìn)行覆蓋式的修改)
public static void blobModify(String infile) throws Exception
{
/* 設(shè)定不自動(dòng)提交 */
boolean defaultCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
try {
/* 查詢BLOB對(duì)象并鎖定 */
ResultSet rs = stmt.executeQuery("SELECT BLOBCOL FROM TEST_BLOB WHERE ID='222' FOR UPDATE");
while (rs.next()) {
/* 取出此BLOB對(duì)象 */
oracle.sql.BLOB blob = (oracle.sql.BLOB)rs.getBlob("BLOBCOL");
/* 向BLOB對(duì)象中寫入數(shù)據(jù) */
BufferedOutputStream out = new BufferedOutputStream(blob.getBinaryOutputStream());
BufferedInputStream in = new BufferedInputStream(new FileInputStream(infile));
int c;
while ((c=in.read())!=-1) {
out.write(c);
}
in.close();
out.close();
}
/* 正式提交 */
conn.commit();
} catch (Exception ex) {
/* 出錯(cuò)回滾 */
conn.rollback();
throw ex;
}
/* 恢復(fù)原提交狀態(tài) */
conn.setAutoCommit(defaultCommit);
}
3、替換BLOB對(duì)象(將原BLOB對(duì)象清除,換成一個(gè)全新的BLOB對(duì)象)
public static void blobReplace(String infile) throws Exception
{
/* 設(shè)定不自動(dòng)提交 */
boolean defaultCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
try {
/* 清空原BLOB對(duì)象 */
stmt.executeUpdate("UPDATE TEST_BLOB SET BLOBCOL=EMPTY_BLOB() WHERE ID='222'");
/* 查詢此BLOB對(duì)象并鎖定 */
ResultSet rs = stmt.executeQuery("SELECT BLOBCOL FROM TEST_BLOB WHERE ID='222' FOR UPDATE");
while (rs.next()) {
/* 取出此BLOB對(duì)象 */
oracle.sql.BLOB blob = (oracle.sql.BLOB)rs.getBlob("BLOBCOL");
/* 向BLOB對(duì)象中寫入數(shù)據(jù) */
BufferedOutputStream out = new BufferedOutputStream(blob.getBinaryOutputStream());
BufferedInputStream in = new BufferedInputStream(new FileInputStream(infile));
int c;
while ((c=in.read())!=-1) {
out.write(c);
}
in.close();
out.close();
}
/* 正式提交 */
conn.commit();
} catch (Exception ex) {
/* 出錯(cuò)回滾 */
conn.rollback();
throw ex;
}
/* 恢復(fù)原提交狀態(tài) */
conn.setAutoCommit(defaultCommit);
}
4、BLOB對(duì)象讀取
public static void blobRead(String outfile) throws Exception
{
/* 設(shè)定不自動(dòng)提交 */
boolean defaultCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
try {
/* 查詢BLOB對(duì)象 */
ResultSet rs = stmt.executeQuery("SELECT BLOBCOL FROM TEST_BLOB WHERE ID='222'");
while (rs.next()) {
/* 取出此BLOB對(duì)象 */
oracle.sql.BLOB blob = (oracle.sql.BLOB)rs.getBlob("BLOBCOL");
/* 以二進(jìn)制形式輸出 */
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outfile));
BufferedInputStream in = new BufferedInputStream(blob.getBinaryStream());
int c;
while ((c=in.read())!=-1) {
out.write(c);
}
in.close();
out.close();
}
/* 正式提交 */
conn.commit();
} catch (Exception ex) {
/* 出錯(cuò)回滾 */
conn.rollback();
throw ex;
}
/* 恢復(fù)原提交狀態(tài) */
conn.setAutoCommit(defaultCommit);
}
觀察上述程序?qū)OB類型字段的存取,我們可以看出,較之其它類型字段,有下面幾個(gè)顯著不同的特點(diǎn):
一是必須取消自動(dòng)提交。
存取操作開始前,必須用setAutoCommit(false)取消自動(dòng)提交。其它類型字段則無此特殊要求。這是因?yàn)榇嫒OB類型字段時(shí),通常要進(jìn)行多次操作可以完成。不這樣的話,Oracle將拋出“讀取違反順序”的錯(cuò)誤。
二是插入方式不同。
LOB數(shù)據(jù)不能象其它類型數(shù)據(jù)一樣直接插入(INSERT)。插入前必須先插入一個(gè)空的LOB對(duì)象,CLOB類型的空對(duì)象為EMPTY_CLOB(),BLOB類型的空對(duì)象為EMPTY_BLOB()。之后通過SELECT命令查詢得到先前插入的記錄并鎖定,繼而將空對(duì)象修改為所要插入的LOB對(duì)象。
三是修改方式不同。
其它類型的字段修改時(shí),用UPDATE … SET…命令即可。而LOB類型字段,則只能用SELECT … FOR UPDATE命令將記錄查詢出來并鎖定,然后才能修改。且修改也有兩種改法:一是在原數(shù)據(jù)基礎(chǔ)上的修改(即覆蓋式修改),執(zhí)行SELECT … FOR UPDATE后再改數(shù)據(jù);二是替換(先將原數(shù)據(jù)清掉,再修改),先執(zhí)行UPDATE命令將LOB字段之值設(shè)為空的LOB對(duì)象,然后進(jìn)行第一種改法。建議使用替換的方法,以實(shí)現(xiàn)與其它字段UPDATE操作后一樣的效果。
四是存取時(shí)應(yīng)使用由數(shù)據(jù)庫(kù)JDBC驅(qū)動(dòng)程序提供的LOB操作類。
對(duì)于Oracle數(shù)據(jù)庫(kù),應(yīng)使用oracle.sql.CLOB和oracle.sql.BLOB。不使用由數(shù)據(jù)庫(kù)JDBC驅(qū)動(dòng)程序提供的LOB類時(shí),程序運(yùn)行時(shí)易于出現(xiàn)“抽象方法調(diào)用”的錯(cuò)誤,這是因?yàn)镴DBC所定義的java.sql.Clob與java.sql.Blob接口,其中的一些方法并未在數(shù)據(jù)庫(kù)廠家提供的驅(qū)動(dòng)程序中真正實(shí)現(xiàn)。
五是存取手段與文件操作相仿。
對(duì)于BLOB類型,應(yīng)用InputStream/OutputStream類,此類不進(jìn)行編碼轉(zhuǎn)換,逐個(gè)字節(jié)存取。oracle.sql.BLOB類相應(yīng)提供了getBinaryStream()和getBinaryOutputStream()兩個(gè)方法,前一個(gè)方法用于讀取Oracle的BLOB字段,后一個(gè)方法用于將數(shù)據(jù)寫入Oracle的BLOB字段。
對(duì)于CLOB類型,應(yīng)用Reader/Writer類,此類進(jìn)行編碼轉(zhuǎn)換。oracle.sql.CLOB類相應(yīng)提供了getCharacterStream()和getCharacterOutputStream()兩個(gè)方法,前一個(gè)方法用于讀取Oracle的CLOB字段,后一個(gè)方法用于將數(shù)據(jù)寫入Oracle的CLOB字段。
需要說明的是,為了大幅提高程序執(zhí)行效率,對(duì)BLOB/CLOB字段的讀寫操作,應(yīng)該使用緩沖操作類(帶Buffered前綴),即:BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter。例程中全部使用了緩沖操作類。
小結(jié):通過JDBC操縱Oracle數(shù)據(jù)庫(kù)的LOB字段,不外乎插入、修改、替換、讀取四種方式,掌握起來并不難。在實(shí)際操作中要注意上面所說的幾點(diǎn),結(jié)合閱讀例程源程序,用戶會(huì)很快明白LOB類型字段的使用的,也必將領(lǐng)悟到這種類型字段的妙處!
posted on 2005-11-16 15:04
瀟瀟雨 閱讀(226)
評(píng)論(0) 編輯 收藏 所屬分類:
JAVA 、
Database