將JavaObject Storage Service到Oracle資料庫中

來源:互聯網
上載者:User

 對象持久化,也就是可以把這個對象永遠的儲存起來,這裡的儲存不僅是對象本身,還包括他的屬性和所依賴的其他類。通常,對象可以持久化到檔案或者是資料庫中。我這裡只介紹如何將Object Storage Service到資料庫中。恰巧Oracle資料庫為我們提供了這樣的方便。

   在Oracle中,有一種blog的欄位類型,它是用來儲存大量的位元據的。我們就利用這個欄位去儲存物件資訊。   首先建立一個測試表:
create table TESTBLOB
(
  NAME    VARCHAR2(50) not null,
  CONTENT BLOB not null,
  ID      NUMBER(8) not null
)alter table TESTBLOB
  add constraint IDFORTEST primary key (ID);

   只用三個欄位,其中id是屬性,content是我們要儲存物件的欄位。

   先來看看我們要存入的對象:

import java.io.Serializable;
import java.util.Date;
import java.util.List;

public class TestObject implements Serializable {
 
 private static final long serialVersionUID = 4558876142427402513L;
 /**
  * @param args
  */
 private String name;
 private String password;
 private Date date;
 private List<City> cityList;
 
 public List<City> getCityList() {
  return cityList;
 }
 public void setCityList(List<City> cityList) {
  this.cityList = cityList;
 }
 public Date getDate() {
  return date;
 }
 public void setDate(Date date) {
  this.date = date;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }
}

    記得要實現Serializable介面,可以看到這是一個包含了string,date,和list類型的對象,為了給測試增加複雜度,我們的list是另外一個對象(city)的list,如下:

import java.io.Serializable;

public class City implements Serializable{
 private static final long serialVersionUID = 4558876127402513L;
 private String name;
 private String code;
 public String getCode() {
  return code;
 }
 public void setCode(String code) {
  this.code = code;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
}

     City對象包括了城市名稱和區號。下面是主要的應用了。

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import oracle.sql.BLOB;

public class Test {

 public static void main(String[] args) {
  //建立測試用對象
  City beijing = new City();
  beijing.setName("北京");
  beijing.setCode("010");
  
  City shanghai = new City();
  shanghai.setName("上海");
  shanghai.setCode("020");
  
  City tianjin = new City();
  tianjin.setName("天津");
  tianjin.setCode("021");
  
  List<City> cityList = new ArrayList<City>();
  cityList.add(beijing);
  cityList.add(shanghai);
  cityList.add(tianjin);
  
  TestObject obj = new TestObject();
  obj.setName("yangsq");
  obj.setPassword("111");
  obj.setDate(new Date());
  obj.setCityList(cityList);
  
  try{
   //將對象存入blob欄位
   ByteArrayOutputStream byteOut=new ByteArrayOutputStream();
   ObjectOutputStream outObj=new ObjectOutputStream(byteOut);
   outObj.writeObject(obj) ;
   final byte[] objbytes=byteOut.toByteArray();
   
   Class.forName("oracle.jdbc.driver.OracleDriver");
   Connection con = DriverManager.getConnection(
     "jdbc:oracle:thin:@***.***.***.***:1521:****", "yangsq", "yangsq");
   con.setAutoCommit(false);
   Statement st = con.createStatement();
   
   st.executeUpdate("insert into TESTBLOB (ID, NAME, CONTENT) values (1, 'test1', empty_blob())");
   ResultSet rs = st.executeQuery("select CONTENT from TESTBLOB where ID=1 for update");
   
   if (rs.next()) {
    BLOB blob = (BLOB) rs.getBlob("CONTENT");
    OutputStream outStream = blob.getBinaryOutputStream();
    outStream.write(objbytes, 0, objbytes.length);
    outStream.flush();
       outStream.close();
   }
   
   byteOut.close();
   outObj.close();
   con.commit();
   
   //取出blob欄位中的對象,並恢複
   rs = st.executeQuery("select CONTENT from TESTBLOB where ID=1");
   BLOB inblob = null;
   if (rs.next()) {
    inblob = (BLOB) rs.getBlob("CONTENT");
   }
   InputStream is = inblob.getBinaryStream();
   BufferedInputStream input = new BufferedInputStream(is);
   
   byte[] buff = new byte[inblob.getBufferSize()];
   while(-1 != (input.read(buff, 0, buff.length)));
   
   ObjectInputStream in =
          new ObjectInputStream(
            new ByteArrayInputStream(
              buff));
   TestObject w3 = (TestObject)in.readObject();
   System.out.println(w3.getName());
   System.out.println(w3.getPassword());
   System.out.println(w3.getDate());
   
   List<City> list = w3.getCityList();
   for(City city : list){
    System.out.println(city.getName() + "    " + city.getCode());
   }
   
   st.close();
   con.close();
  } catch (Exception ex) {
   ex.printStackTrace();
   System.exit(1);
  }
 }
}

  代碼的藍色部分建立了要儲存的對象。再看紅色的對象寫入部分,它首先把對象轉化成二進位流的形式。對於blob欄位,我們不能簡單的在insert時插入,實際上,insert時,對於blob欄位,只能先插入一個空的blob對象empty_blob(),然後再進行"select CONTENT from TESTBLOB where ID=1 for update"對blob欄位進行更新。返回後,我們只要把對象的二進位流寫入即可。

OutputStream outStream = blob.getBinaryOutputStream();
outStream.write(objbytes, 0, objbytes.length);

  需要注意的是,上述步驟必須設定con.setAutoCommit(false),否則oracle會拋出異常。

  接下來,綠色的代碼是讀取資料庫中blob欄位的對象,並恢複。我們要知道的是,所有對blob欄位的操作都是二進位的,即插入時是二進位流,讀出時也是二進位流。然後用io修飾器(ObjectInputStream)去修飾。以前學習java時,感覺它的io好繁瑣啊,現在感覺還真是各有其用。下面是測試的輸出結果。

yangsq
111
Tue Mar 27 12:11:28 CST 2007
北京    010
上海    020
天津    021

    需要說明一下,buff的size一定要足夠大,否則將拋出異常。在這裡,我使用的是inblob.getBufferSize()來設定buff的size,這並不是一種好的方法,因為一般inblob.getBufferSize()都是32768,很可能出現異常,所以這個size最好自己設定,或系統運行時刻設定(幸好java提供數組長度的運行時刻設定)。

上面是我本人研究的結果,當然少不了網友們的知識奉獻。下面就轉自一位網友的blog。

轉:

1.建立記錄,插入BLOB資料
 1.1首先建立記錄的時候,使用oracle的函數插入一個空的BLOB,假設欄位A是BLOB類型的:
  insert xxxtable(A,B,C) values(empty_blob(),'xxx','yyyy')
 1.2後面再查詢剛才插入的記錄,然後更新BLOB,在查詢前,注意設定Connection的一個屬性:
  conn.setAutoCommit(false);如果缺少這一步,可能導致fetch out of sequence等異常.
 1.3 查詢剛才插入的記錄,後面要加“ for update ”,如下:
  select A from xxxtable where xxx=999 for update ,如果缺少for update,可能出現row containing the LOB value is not locked

的異常
 1.4 從查詢到的 BLOB欄位中,擷取blob並進行更新,代碼如下:
  BLOB blob = (BLOB) rs.getBlob("A");
  OutputStream os = blob.getBinaryOutputStream();
  BufferedOutputStream output = new BufferedOutputStream(os);

  後面再使用output.write方法將需要寫入的內容寫到output中就可以了。例如我們將一個檔案寫入這個欄位中:
  BufferedInputStream input = new BufferedInputStream(new File("c://hpWave.log").toURL().openStream());
  byte[] buff = new byte[2048];  //用做檔案寫入的緩衝
  int bytesRead;
  while(-1 != (bytesRead = input.read(buff, 0, buff.length))) {
   output.write(buff, 0, bytesRead);
   System.out.println(bytesRead);
  }
  上面的代碼就是從input裡2k地讀取,然後寫入到output中。
 1.5上面執行完畢後,記得關閉output,input,以及關閉查詢到的ResultSet
 1.6最後執行conn.commit();將更新的內容提交,以及執行conn.setAutoCommit(true); 改回Connction的屬性
2.修改記錄,方法與上面的方法類似,
 2.1首先更新BLOB以外的其他欄位
 2.2 使用1.3中類似的方法擷取記錄
 2.3 修改的過程中,注意以下:a 需要更新的記錄中,BLOB有可能為NULL,這樣在執行blob.getBinaryOutputStream()擷取的值可能為

null,那麼就關閉剛才select的記錄,再執行一次update xxxtable set A = empty_blob() where xxx, 這樣就先寫入了一個空的BLOB(不是null),然後再

使用1.3,1.4中的方法執行更新記錄.b 注意別忘了先執行setAutoCommit(false),以及"for update",以及後面的conn.commit();等。
3.讀取BLOB欄位中的資料.
 3.1 讀取記錄不需要setAutoCommit(),以及 select ....for update.
 3.2 使用普通的select 方法查詢出記錄
 3.3 從ResultSet中擷取BLOB並讀取,如下:
  BLOB b_to = (BLOB) rs.getBlob("A");
  InputStream is = b_from.getBinaryStream();
  BufferedInputStream input = new BufferedInputStream(is);
  byte[] buff = new byte[2048];
  while(-1 != (bytesRead = input.read(buff, 0, buff.length))) {
   //在這裡執行寫入,如寫入到檔案的BufferedOutputStream裡
   System.out.println(bytesRead);
  }
  通過迴圈取出blob中的資料,寫到buff裡,再將buff的內容寫入到需要的地方
4.兩個資料庫間blob欄位的傳輸
類似上面1和3的方法,一邊擷取BufferedOutputStream,另外一邊擷取BufferedInputStream,然後讀出寫入,需要注意的是寫入所用的

Connection要執行conn.setAutoCommit(false);以及擷取記錄時添加“ for update ”以及最後的commit();

總結以上方法,其根本就是先建立空的BLOB,再擷取其BufferedOutputStream進行寫入,或擷取BufferedInputStream進行讀取

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.