Java对象存储到Oracle数据库


对象持久化,也就是可以把这个对象永远的保存起来,这里的保存不仅是对象本身,还包括他的属性和所依赖的其他类。通常,对象可以持久化到文件或者是数据库中。我这里只介绍如何将对象存储到数据库中。恰巧Oracle数据库为我们提供了这样的方便。

在Oracle中,有一种blog的字段类型,它是用来存储大量的二进制数据的。我们就利用这个字段去存储对象信息。

首先建立一个测试表:

  1. create table TESTBLOB  
  2. (  
  3.   NAME    VARCHAR2(50) not null,  
  4.   CONTENT BLOB not null,  
  5.   ID      NUMBER(8) not null  
  6. )alter table TESTBLOB  
  7.   add constraint IDFORTEST primary key (ID);  
  8.   
  9.    只用三个字段,其中id是属性,content是我们要存储对象的字段。  
  10.   
  11.    先来看看我们要存入的对象:  
  12.   
  13. import java.io.Serializable;  
  14. import java.util.Date;  
  15. import java.util.List;  
  16.   
  17. public class TestObject implements Serializable {  
  18.    
  19.  private static final long serialVersionUID = 4558876142427402513L;  
  20.  /** 
  21.   * @param args 
  22.   */  
  23.  private String name;  
  24.  private String password;  
  25.  private Date date;  
  26.  private List<City> cityList;  
  27.    
  28.  public List<City> getCityList() {  
  29.   return cityList;  
  30.  }  
  31.  public void setCityList(List<City> cityList) {  
  32.   this.cityList = cityList;  
  33.  }  
  34.  public Date getDate() {  
  35.   return date;  
  36.  }  
  37.  public void setDate(Date date) {  
  38.   this.date = date;  
  39.  }  
  40.  public String getName() {  
  41.   return name;  
  42.  }  
  43.  public void setName(String name) {  
  44.   this.name = name;  
  45.  }  
  46.  public String getPassword() {  
  47.   return password;  
  48.  }  
  49.  public void setPassword(String password) {  
  50.   this.password = password;  
  51.  }  
  52. }  
  53.     记得要实现Serializable接口,可以看到这是一个包含了string,date,和list类型的对象,为了给测试增加复杂度,我们的list是另外一个对象(city)的list,如下:  
  54.   
  55. import java.io.Serializable;  
  56.   
  57. public class City implements Serializable{  
  58.  private static final long serialVersionUID = 4558876127402513L;  
  59.  private String name;  
  60.  private String code;  
  61.  public String getCode() {  
  62.   return code;  
  63.  }  
  64.  public void setCode(String code) {  
  65.   this.code = code;  
  66.  }  
  67.  public String getName() {  
  68.   return name;  
  69.  }  
  70.  public void setName(String name) {  
  71.   this.name = name;  
  72.  }  
  73. }  
  74.   
  75.      City对象包括了城市名称和区号。下面是主要的应用了。  
  76.   
  77. import java.io.BufferedInputStream;  
  78. import java.io.ByteArrayInputStream;  
  79. import java.io.ByteArrayOutputStream;  
  80. import java.io.InputStream;  
  81. import java.io.ObjectInputStream;  
  82. import java.io.ObjectOutputStream;  
  83. import java.io.OutputStream;  
  84. import java.sql.Connection;  
  85. import java.sql.DriverManager;  
  86. import java.sql.ResultSet;  
  87. import java.sql.Statement;  
  88. import java.util.ArrayList;  
  89. import java.util.Date;  
  90. import java.util.List;  
  91.   
  92. import oracle.sql.BLOB;  
  93.   
  94. public class Test {  
  95.   
  96.  public static void main(String[] args) {  
  97.   //创建测试用对象   
  98.   City beijing = new City();  
  99.   beijing.setName("北京");  
  100.   beijing.setCode("010");  
  101.     
  102.   City shanghai = new City();  
  103.   shanghai.setName("上海");  
  104.   shanghai.setCode("020");  
  105.     
  106.   City tianjin = new City();  
  107.   tianjin.setName("天津");  
  108.   tianjin.setCode("021");  
  109.     
  110.   List<City> cityList = new ArrayList<City>();  
  111.   cityList.add(beijing);  
  112.   cityList.add(shanghai);  
  113.   cityList.add(tianjin);  
  114.     
  115.   TestObject obj = new TestObject();  
  116.   obj.setName("yangsq");  
  117.   obj.setPassword("111");  
  118.   obj.setDate(new Date());  
  119.   obj.setCityList(cityList);  
  120.     
  121.   try{  
  122.    //将对象存入blob字段   
  123.    ByteArrayOutputStream byteOut=new ByteArrayOutputStream();  
  124.    ObjectOutputStream outObj=new ObjectOutputStream(byteOut);  
  125.    outObj.writeObject(obj) ;  
  126.    final byte[] objbytes=byteOut.toByteArray();  
  127.      
  128.    Class.forName("oracle.jdbc.driver.OracleDriver");  
  129.    Connection con = DriverManager.getConnection(  
  130.      "jdbc:oracle:thin:@***.***.***.***:1521:****""yangsq""yangsq");  
  131.    con.setAutoCommit(false);  
  132.    Statement st = con.createStatement();  
  133.      
  134.    st.executeUpdate("insert into TESTBLOB (ID, NAME, CONTENT) values (1, 'test1', empty_blob())");  
  135.    ResultSet rs = st.executeQuery("select CONTENT from TESTBLOB where ID=1 for update");  
  136.      
  137.    if (rs.next()) {  
  138.     BLOB blob = (BLOB) rs.getBlob("CONTENT");  
  139.     OutputStream outStream = blob.getBinaryOutputStream();  
  140.     outStream.write(objbytes, 0, objbytes.length);  
  141.     outStream.flush();  
  142.        outStream.close();  
  143.    }  
  144.      
  145.    byteOut.close();  
  146.    outObj.close();  
  147.    con.commit();  
  148.      
  149.    //取出blob字段中的对象,并恢复   
  150.    rs = st.executeQuery("select CONTENT from TESTBLOB where ID=1");  
  151.    BLOB inblob = null;  
  152.    if (rs.next()) {  
  153.     inblob = (BLOB) rs.getBlob("CONTENT");  
  154.    }  
  155.    InputStream is = inblob.getBinaryStream();  
  156.    BufferedInputStream input = new BufferedInputStream(is);  
  157.      
  158.    byte[] buff = new byte[inblob.getBufferSize()];  
  159.    while(-1 != (input.read(buff, 0, buff.length)));  
  160.      
  161.    ObjectInputStream in =  
  162.           new ObjectInputStream(  
  163.             new ByteArrayInputStream(  
  164.               buff));  
  165.    TestObject w3 = (TestObject)in.readObject();  
  166.    System.out.println(w3.getName());  
  167.    System.out.println(w3.getPassword());  
  168.    System.out.println(w3.getDate());  
  169.      
  170.    List<City> list = w3.getCityList();  
  171.    for(City city : list){  
  172.     System.out.println(city.getName() + "    " + city.getCode());  
  173.    }  
  174.      
  175.    st.close();  
  176.    con.close();  
  177.   } catch (Exception ex) {  
  178.    ex.printStackTrace();  
  179.    System.exit(1);  
  180.   }  
  181.  }  
  182. }  
  183.   代码的蓝色部分创建了要存储的对象。再看红色的对象写入部分,它首先把对象转化成二进制流的形式。对于blob字段,我们不能简单的在insert时插入,实际上,insert时,对于blob字段,只能先插入一个空的blob对象empty_blob(),然后再进行"select CONTENT from TESTBLOB where ID=1 for update"对blob字段进行更新。返回后,我们只要把对象的二进制流写入即可。  
  184. OutputStream outStream = blob.getBinaryOutputStream();  
  185. outStream.write(objbytes, 0, objbytes.length);  
  186.   
  187.   需要注意的是,上述步骤必须设置con.setAutoCommit(false),否则oracle会抛出异常。  
  188.   
  189.   接下来,绿色的代码是读取数据库中blob字段的对象,并恢复。我们要知道的是,所有对blob字段的操作都是二进制的,即插入时是二进制流,读出时也是二进制流。然后用io修饰器(ObjectInputStream)去修饰。以前学习java时,感觉它的io好繁琐啊,现在感觉还真是各有其用。下面是测试的输出结果。  
  190. yangsq  
  191. 111  
  192. Tue Mar 27 12:11:28 CST 2007  
  193. 北京    010  
  194. 上海    020  
  195. 天津    021  
  196.   
  197.     需要说明一下,buff的size一定要足够大,否则将抛出异常。在这里,我使用的是inblob.getBufferSize()来设置buff的size,这并不是一种好的方法,因为一般inblob.getBufferSize()都是32768,很可能出现异常,所以这个size最好自己设置,或系统运行时刻设置(幸好java提供数组长度的运行时刻设置)。  
  198.   
  199. 上面是我本人研究的结果,当然少不了网友们的知识奉献。下面就转自一位网友的blog。  
  200.   
  201. 转:  
  202.   
  203. 1.新建记录,插入BLOB数据  
  204.  1.1首先新建记录的时候,使用oracle的函数插入一个空的BLOB,假设字段A是BLOB类型的:  
  205.   insert xxxtable(A,B,C) values(empty_blob(),'xxx','yyyy')  
  206.  1.2后面再查询刚才插入的记录,然后更新BLOB,在查询前,注意设置Connection的一个属性:  
  207.   conn.setAutoCommit(false);如果缺少这一步,可能导致fetch out of sequence等异常.  
  208.  1.3 查询刚才插入的记录,后面要加“ for update ”,如下:  
  209.   select A from xxxtable where xxx=999 for update ,如果缺少for update,可能出现row containing the LOB value is not locked  
  210.   
  211. 的异常  
  212.  1.4 从查询到的 BLOB字段中,获取blob并进行更新,代码如下:  
  213.   BLOB blob = (BLOB) rs.getBlob("A");  
  214.   OutputStream os = blob.getBinaryOutputStream();  
  215.   BufferedOutputStream output = new BufferedOutputStream(os);  
  216.   
  217.   后面再使用output.write方法将需要写入的内容写到output中就可以了。例如我们将一个文件写入这个字段中:  
  218.   BufferedInputStream input = new BufferedInputStream(new File("c:\hpWave.log").toURL().openStream());  
  219.   byte[] buff = new byte[2048];  //用做文件写入的缓冲   
  220.   int bytesRead;  
  221.   while(-1 != (bytesRead = input.read(buff, 0, buff.length))) {  
  222.    output.write(buff, 0, bytesRead);  
  223.    System.out.println(bytesRead);  
  224.   }  
  225.   上面的代码就是从input里2k地读取,然后写入到output中。  
  226.  1.5上面执行完毕后,记得关闭output,input,以及关闭查询到的ResultSet  
  227.  1.6最后执行conn.commit();将更新的内容提交,以及执行conn.setAutoCommit(true); 改回Connction的属性  
  228. 2.修改记录,方法与上面的方法类似,  
  229.  2.1首先更新BLOB以外的其他字段  
  230.  2.2 使用1.3中类似的方法获取记录  
  231.  2.3 修改的过程中,注意以下:a 需要更新的记录中,BLOB有可能为NULL,这样在执行blob.getBinaryOutputStream()获取的值可能为  
  232.   
  233. null,那么就关闭刚才select的记录,再执行一次update xxxtable set A = empty_blob() where xxx, 这样就先写入了一个空的BLOB(不是null),然后再  
  234.   
  235. 使用1.3,1.4中的方法执行更新记录.b 注意别忘了先执行setAutoCommit(false),以及"for update",以及后面的conn.commit();等。  
  236. 3.读取BLOB字段中的数据.  
  237.  3.1 读取记录不需要setAutoCommit(),以及 select ....for update.  
  238.  3.2 使用普通的select 方法查询出记录  
  239.  3.3 从ResultSet中获取BLOB并读取,如下:  
  240.   BLOB b_to = (BLOB) rs.getBlob("A");  
  241.   InputStream is = b_from.getBinaryStream();  
  242.   BufferedInputStream input = new BufferedInputStream(is);  
  243.   byte[] buff = new byte[2048];  
  244.   while(-1 != (bytesRead = input.read(buff, 0, buff.length))) {  
  245.    //在这里执行写入,如写入到文件的BufferedOutputStream里   
  246.    System.out.println(bytesRead);  
  247.   }  
  248.   通过循环取出blob中的数据,写到buff里,再将buff的内容写入到需要的地方  
  249. 4.两个数据库间blob字段的传输  
  250. 类似上面13的方法,一边获取BufferedOutputStream,另外一边获取BufferedInputStream,然后读出写入,需要注意的是写入所用的  
  251.   
  252. Connection要执行conn.setAutoCommit(false);以及获取记录时添加“ for update ”以及最后的commit();  
  253.   
  254. 总结以上方法,其根本就是先创建空的BLOB,再获取其BufferedOutputStream进行写入,或获取BufferedInputStream进行读取  

相关内容