1. 程式人生 > >java 關於操作oracle的clob型別(inster ,update,select)的完整例程

java 關於操作oracle的clob型別(inster ,update,select)的完整例程

在Oracle中,LOB(Large Object,大型物件)型別的欄位現在用得越來越多了。因為這種型別的欄位,容量大(最多能容納4GB的資料),且一個表中可以有多個這種型別的欄位,很靈活,適用於資料量非常大的業務領域(如圖象、檔案等)。而LONG、LONG RAW等型別的欄位,雖然儲存容量也不小(可達2GB),但由於一個表中只能有一個這樣型別的欄位的限制,現在已很少使用了。

    LOB型別分為BLOB和CLOB兩種:BLOB即二進位制大型物件(Binary Large Object),適用於存貯非文字的位元組流資料(如程式、圖象、影音等)。而CLOB,即字元型大型物件(Character Large Object),則與字符集相關,適於存貯文字型的資料(如歷史檔案、大部頭著作等)。

    下面以程式例項說明通過JDBC操縱Oracle資料庫LOB型別欄位的幾種情況。

    先建立如下兩個測試用的資料庫表,Power Designer PD模型如下:

    建表SQL語句為:

CREATE TABLE TEST_CLOB ( ID NUMBER(3), CLOBCOL CLOB)
CREATE TABLE TEST_BLOB ( ID NUMBER(3), BLOBCOL BLOB)

一、 CLOB物件的存取

1、往資料庫中插入一個新的CLOB物件

 public static void clobInsert(String infile) throws Exception
 {
  /* 設定不自動提交 */
  boolean defaultCommit = conn.getAutoCommit();
  conn.setAutoCommit(false);
  try
  {
   /* 插入一個空的CLOB物件 */
   stmt.executeUpdate("INSERT INTO TEST_CLOB VALUES (''''111'''', EMPTY_CLOB())");
   /* 查詢此CLOB物件並鎖定 */
   ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID=''''111'''' FOR UPDATE");

   while (rs.next())
   {
    /* 取出此CLOB物件 */
    oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");
    /* 向CLOB物件中寫入資料 */
    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)
  {
   conn.rollback();// 出錯回滾
   throw ex;
  }
  conn.setAutoCommit(defaultCommit);// 恢復原提交狀態
  }

 2、修改CLOB物件(是在原CLOB物件基礎上進行覆蓋式的修改)

 public static void clobModify(String infile) throws Exception
 {
  /* 設定不自動提交 */
  boolean defaultCommit = conn.getAutoCommit();
  conn.setAutoCommit(false);
  try
  {
   /* 查詢CLOB物件並鎖定 */
   ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID=''''111'''' FOR UPDATE");
   while (rs.next())
   {
    /* 獲取此CLOB物件 */
    oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");
    /* 進行覆蓋式修改 */
    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)
  {
   conn.rollback();// 出錯回滾
   throw ex;
  }
  conn.setAutoCommit(defaultCommit);// 恢復原提交狀態
 }
 
 3、替換CLOB物件(將原CLOB物件清除,換成一個全新的CLOB物件)
 public static void clobReplace(String infile) throws Exception
 {
  /* 設定不自動提交 */
  boolean defaultCommit = conn.getAutoCommit();
  conn.setAutoCommit(false);
  try
  {
   /* 清空原CLOB物件 */
   stmt.executeUpdate("UPDATE TEST_CLOB SET CLOBCOL=EMPTY_CLOB() WHERE ID=''''111''''");
   /* 查詢CLOB物件並鎖定 */
   ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID=''''111'''' FOR UPDATE");
   while (rs.next())
   {
    /* 獲取此CLOB物件 */
    oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");
    /* 更新資料 */
    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)
  {
    conn.rollback();// 出錯回滾
    throw ex;
  }
  conn.setAutoCommit(defaultCommit);// 恢復原提交狀態
 }

 4、CLOB物件讀取
 public static void clobRead(String outfile) throws Exception
 {
  /* 設定不自動提交 */
  boolean defaultCommit = conn.getAutoCommit();
  conn.setAutoCommit(false);
  try
  {
   /* 查詢CLOB物件 */
   ResultSet rs = stmt.executeQuery("SELECT * FROM TEST_CLOB WHERE ID=''''111''''");
   while (rs.next())
   {
    /* 獲取CLOB物件 */
    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;
  }
  conn.setAutoCommit(defaultCommit);// 恢復原提交狀態
 }

 二、 BLOB物件的存取

 1、 向資料庫中插入一個新的BLOB物件
 public static void blobInsert(String infile) throws Exception
 {
  /* 設定不自動提交 */
  boolean defaultCommit = conn.getAutoCommit();
  conn.setAutoCommit(false);
  try
  {
   /* 插入一個空的BLOB物件 */
   stmt.executeUpdate("INSERT INTO TEST_BLOB VALUES (''''222'''', EMPTY_BLOB())");
   /* 查詢此BLOB物件並鎖定 */
   ResultSet rs = stmt.executeQuery("SELECT BLOBCOL FROM TEST_BLOB WHERE ID=''''222'''' FOR UPDATE");
   while (rs.next())
   {
    /* 取出此BLOB物件 */
    oracle.sql.BLOB blob = (oracle.sql.BLOB)rs.getBlob("BLOBCOL");
    /* 向BLOB物件中寫入資料 */
    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)
  {
   conn.rollback();// 出錯回滾
   throw ex;
  }
  conn.setAutoCommit(defaultCommit);// 恢復原提交狀態
 }

 2、修改BLOB物件(是在原BLOB物件基礎上進行覆蓋式的修改)
 public static void blobModify(String infile) throws Exception
 {
  /* 設定不自動提交 */
  boolean defaultCommit = conn.getAutoCommit();
  conn.setAutoCommit(false);
  try
  {
   /* 查詢BLOB物件並鎖定 */
   ResultSet rs = stmt.executeQuery("SELECT BLOBCOL FROM TEST_BLOB WHERE ID=''''222'''' FOR UPDATE");
   while (rs.next())
   {
    /* 取出此BLOB物件 */
    oracle.sql.BLOB blob = (oracle.sql.BLOB)rs.getBlob("BLOBCOL");
    /* 向BLOB物件中寫入資料 */
    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)
  {
  conn.rollback();// 出錯回滾
  throw ex;
  }
  conn.setAutoCommit(defaultCommit);// 恢復原提交狀態
 }

 3、替換BLOB物件(將原BLOB物件清除,換成一個全新的BLOB物件)

 public static void blobReplace(String infile) throws Exception
 {
  /* 設定不自動提交 */
  boolean defaultCommit = conn.getAutoCommit();
  conn.setAutoCommit(false);
  try
  {
   /* 清空原BLOB物件 */
   stmt.executeUpdate("UPDATE TEST_BLOB SET BLOBCOL=EMPTY_BLOB() WHERE ID=''''222''''");
   /* 查詢此BLOB物件並鎖定 */
   ResultSet rs = stmt.executeQuery("SELECT BLOBCOL FROM TEST_BLOB WHERE ID=''''222'''' FOR UPDATE");
   while (rs.next())
   {
    /* 取出此BLOB物件 */
    oracle.sql.BLOB blob = (oracle.sql.BLOB)rs.getBlob("BLOBCOL");
    /* 向BLOB物件中寫入資料 */
    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)
  {
  conn.rollback();// 出錯回滾
  throw ex;
  }
  conn.setAutoCommit(defaultCommit);// 恢復原提交狀態
 }

 4、BLOB物件讀取
 public static void blobRead(String outfile) throws Exception
 {
  /* 設定不自動提交 */
  boolean defaultCommit = conn.getAutoCommit();
  conn.setAutoCommit(false);
  try
  {
   /* 查詢BLOB物件 */
   ResultSet rs = stmt.executeQuery("SELECT BLOBCOL FROM TEST_BLOB WHERE ID=''''222''''");
   while (rs.next())
   {
    /* 取出此BLOB物件 */
    oracle.sql.BLOB blob = (oracle.sql.BLOB)rs.getBlob("BLOBCOL");
    /* 以二進位制形式輸出 */
    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)
  {
   conn.rollback();// 出錯回滾
   throw ex;
  }
  conn.setAutoCommit(defaultCommit);// 恢復原提交狀態
 }

    觀察上述程式對LOB型別欄位的存取,我們可以看出,較之其它型別欄位,有下面幾個顯著不同的特點:

    一是必須取消自動提交。
    存取操作開始前,必須用setAutoCommit(false)取消自動提交。其它型別欄位則無此特殊要求。這是因為存取LOB型別欄位時,通常要進行多次操作可以完成。不這樣的話,Oracle將丟擲“讀取違反順序”的錯誤。

    二是插入方式不同。
    LOB資料不能象其它型別資料一樣直接插入(INSERT)。插入前必須先插入一個空的LOB物件,CLOB型別的空物件為EMPTY_CLOB(),BLOB型別的空物件為EMPTY_BLOB()。之後通過SELECT命令查詢得到先前插入的記錄並鎖定,繼而將空物件修改為所要插入的LOB物件。

    三是修改方式不同。
    其它型別的欄位修改時,用UPDATE … SET…命令即可。而LOB型別欄位,則只能用SELECT … FOR UPDATE命令將記錄查詢出來並鎖定,然後才能修改。且修改也有兩種改法:一是在原資料基礎上的修改(即覆蓋式修改),執行SELECT … FOR UPDATE後再改資料;二是替換(先將原資料清掉,再修改),先執行UPDATE命令將LOB欄位之值設為空的LOB物件,然後進行第一種改法。建議使用替換的方法,以實現與其它欄位UPDATE操作後一樣的效果。

    四是存取時應使用由資料庫JDBC驅動程式提供的LOB操作類。
    對於Oracle資料庫,應使用oracle.sql.CLOB和oracle.sql.BLOB。不使用由資料庫JDBC驅動程式提供的LOB類時,程式執行時易於出現“抽象方法呼叫”的錯誤,這是因為JDBC所定義的java.sql.Clob與java.sql.Blob介面,其中的一些方法並未在資料庫廠家提供的驅動程式中真正實現。

    五是存取手段與檔案操作相仿。
    對於BLOB型別,應用InputStream/OutputStream類,此類不進行編碼轉換,逐個位元組存取。oracle.sql.BLOB類相應提供了getBinaryStream()和getBinaryOutputStream()兩個方法,前一個方法用於讀取Oracle的BLOB欄位,後一個方法用於將資料寫入Oracle的BLOB欄位。

    對於CLOB型別,應用Reader/Writer類,此類進行編碼轉換。oracle.sql.CLOB類相應提供了getCharacterStream()和getCharacterOutputStream()兩個方法,前一個方法用於讀取Oracle的CLOB欄位,後一個方法用於將資料寫入Oracle的CLOB欄位。

    需要說明的是,為了大幅提高程式執行效率,對BLOB/CLOB欄位的讀寫操作,應該使用緩衝操作類(帶Buffered字首),即:BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter。例程中全部使用了緩衝操作類。

    小結:通過JDBC操縱Oracle資料庫的LOB欄位,不外乎插入、修改、替換、讀取四種方式,掌握起來並不難。在實際操作中要注意上面所說的幾點,結合閱讀例程源程式,使用者會很快明白LOB型別欄位的使用的,也必將領悟到這種型別欄位的妙處!