将Java对象存储到Oracle数据库中

mikean 2010-03-30

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

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

首先建立一个测试表:

createtableTESTBLOB

(

NAMEVARCHAR2(50)notnull,

CONTENTBLOBnotnull,

IDNUMBER(8)notnull

)altertableTESTBLOB

addconstraintIDFORTESTprimarykey(ID);

只用三个字段,其中id是属性,content是我们要存储对象的字段。

先来看看我们要存入的对象:

importjava.io.Serializable;

importjava.util.Date;

importjava.util.List;

publicclassTestObjectimplementsSerializable{

privatestaticfinallongserialVersionUID=4558876142427402513L;

/**

*@paramargs

*/

privateStringname;

privateStringpassword;

privateDatedate;

privateList<City>cityList;

publicList<City>getCityList(){

returncityList;

}

publicvoidsetCityList(List<City>cityList){

this.cityList=cityList;

}

publicDategetDate(){

returndate;

}

publicvoidsetDate(Datedate){

this.date=date;

}

publicStringgetName(){

returnname;

}

publicvoidsetName(Stringname){

this.name=name;

}

publicStringgetPassword(){

returnpassword;

}

publicvoidsetPassword(Stringpassword){

this.password=password;

}

}

记得要实现Serializable接口,可以看到这是一个包含了string,date,和list类型的对象,为了给测试增加复杂度,我们的list是另外一个对象(city)的list,如下:

importjava.io.Serializable;

publicclassCityimplementsSerializable{

privatestaticfinallongserialVersionUID=4558876127402513L;

privateStringname;

privateStringcode;

publicStringgetCode(){

returncode;

}

publicvoidsetCode(Stringcode){

this.code=code;

}

publicStringgetName(){

returnname;

}

publicvoidsetName(Stringname){

this.name=name;

}

}

City对象包括了城市名称和区号。下面是主要的应用了。

importjava.io.BufferedInputStream;

importjava.io.ByteArrayInputStream;

importjava.io.ByteArrayOutputStream;

importjava.io.InputStream;

importjava.io.ObjectInputStream;

importjava.io.ObjectOutputStream;

importjava.io.OutputStream;

importjava.sql.Connection;

importjava.sql.DriverManager;

importjava.sql.ResultSet;

importjava.sql.Statement;

importjava.util.ArrayList;

importjava.util.Date;

importjava.util.List;

importoracle.sql.BLOB;

publicclassTest{

publicstaticvoidmain(String[]args){

//创建测试用对象

Citybeijing=newCity();

beijing.setName("北京");

beijing.setCode("010");

Cityshanghai=newCity();

shanghai.setName("上海");

shanghai.setCode("020");

Citytianjin=newCity();

tianjin.setName("天津");

tianjin.setCode("021");

List<City>cityList=newArrayList<City>();

cityList.add(beijing);

cityList.add(shanghai);

cityList.add(tianjin);

TestObjectobj=newTestObject();

obj.setName("yangsq");

obj.setPassword("111");

obj.setDate(newDate());

obj.setCityList(cityList);

try{

//将对象存入blob字段

ByteArrayOutputStreambyteOut=newByteArrayOutputStream();

ObjectOutputStreamoutObj=newObjectOutputStream(byteOut);

outObj.writeObject(obj);

finalbyte[]objbytes=byteOut.toByteArray();

Class.forName("oracle.jdbc.driver.OracleDriver");

Connectioncon=DriverManager.getConnection(

"jdbc:oracle:thin:@***.***.***.***:1521:****","yangsq","yangsq");

con.setAutoCommit(false);

Statementst=con.createStatement();

st.executeUpdate("insertintoTESTBLOB(ID,NAME,CONTENT)values(1,'test1',empty_blob())");

ResultSetrs=st.executeQuery("selectCONTENTfromTESTBLOBwhereID=1forupdate");

if(rs.next()){

BLOBblob=(BLOB)rs.getBlob("CONTENT");

OutputStreamoutStream=blob.getBinaryOutputStream();

outStream.write(objbytes,0,objbytes.length);

outStream.flush();

outStream.close();

}

byteOut.close();

outObj.close();

con.commit();

//取出blob字段中的对象,并恢复

rs=st.executeQuery("selectCONTENTfromTESTBLOBwhereID=1");

BLOBinblob=null;

if(rs.next()){

inblob=(BLOB)rs.getBlob("CONTENT");

}

InputStreamis=inblob.getBinaryStream();

BufferedInputStreaminput=newBufferedInputStream(is);

byte[]buff=newbyte[inblob.getBufferSize()];

while(-1!=(input.read(buff,0,buff.length)));

ObjectInputStreamin=

newObjectInputStream(

newByteArrayInputStream(

buff));

TestObjectw3=(TestObject)in.readObject();

System.out.println(w3.getName());

System.out.println(w3.getPassword());

System.out.println(w3.getDate());

List<City>list=w3.getCityList();

for(Citycity:list){

System.out.println(city.getName()+""+city.getCode());

}

st.close();

con.close();

}catch(Exceptionex){

ex.printStackTrace();

System.exit(1);

}

}

}

代码的蓝色部分创建了要存储的对象。再看红色的对象写入部分,它首先把对象转化成二进制流的形式。对于blob字段,我们不能简单的在insert时插入,实际上,insert时,对于blob字段,只能先插入一个空的blob对象empty_blob(),然后再进行"selectCONTENTfromTESTBLOBwhereID=1forupdate"对blob字段进行更新。返回后,我们只要把对象的二进制流写入即可。

OutputStreamoutStream=blob.getBinaryOutputStream();

outStream.write(objbytes,0,objbytes.length);

需要注意的是,上述步骤必须设置con.setAutoCommit(false),否则oracle会抛出异常。

接下来,绿色的代码是读取数据库中blob字段的对象,并恢复。我们要知道的是,所有对blob字段的操作都是二进制的,即插入时是二进制流,读出时也是二进制流。然后用io修饰器(ObjectInputStream)去修饰。以前学习java时,感觉它的io好繁琐啊,现在感觉还真是各有其用。下面是测试的输出结果。

yangsq

111

TueMar2712:11:28CST2007

北京010

上海020

天津021

需要说明一下,buff的size一定要足够大,否则将抛出异常。在这里,我使用的是inblob.getBufferSize()来设置buff的size,这并不是一种好的方法,因为一般inblob.getBufferSize()都是32768,很可能出现异常,所以这个size最好自己设置,或系统运行时刻设置(幸好java提供数组长度的运行时刻设置)。

上面是我本人研究的结果,当然少不了网友们的知识奉献。下面就转自一位网友的blog。

转:

1.新建记录,插入BLOB数据

1.1首先新建记录的时候,使用oracle的函数插入一个空的BLOB,假设字段A是BLOB类型的:

insertxxxtable(A,B,C)values(empty_blob(),'xxx','yyyy')

1.2后面再查询刚才插入的记录,然后更新BLOB,在查询前,注意设置Connection的一个属性:

conn.setAutoCommit(false);如果缺少这一步,可能导致fetchoutofsequence等异常.

1.3查询刚才插入的记录,后面要加“forupdate”,如下:

selectAfromxxxtablewherexxx=999forupdate,如果缺少forupdate,可能出现rowcontainingtheLOBvalueisnotlocked

的异常

1.4从查询到的BLOB字段中,获取blob并进行更新,代码如下:

BLOBblob=(BLOB)rs.getBlob("A");

OutputStreamos=blob.getBinaryOutputStream();

BufferedOutputStreamoutput=newBufferedOutputStream(os);

后面再使用output.write方法将需要写入的内容写到output中就可以了。例如我们将一个文件写入这个字段中:

BufferedInputStreaminput=newBufferedInputStream(newFile("c:\\hpWave.log").toURL().openStream());

byte[]buff=newbyte[2048];//用做文件写入的缓冲

intbytesRead;

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的记录,再执行一次updatexxxtablesetA=empty_blob()wherexxx,这样就先写入了一个空的BLOB(不是null),然后再

使用1.3,1.4中的方法执行更新记录.b注意别忘了先执行setAutoCommit(false),以及"forupdate",以及后面的conn.commit();等。

3.读取BLOB字段中的数据.

3.1读取记录不需要setAutoCommit(),以及select....forupdate.

3.2使用普通的select方法查询出记录

3.3从ResultSet中获取BLOB并读取,如下:

BLOBb_to=(BLOB)rs.getBlob("A");

InputStreamis=b_from.getBinaryStream();

BufferedInputStreaminput=newBufferedInputStream(is);

byte[]buff=newbyte[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);以及获取记录时添加“forupdate”以及最后的commit();

总结以上方法,其根本就是先创建空的BLOB,再获取其BufferedOutputStream进行写入,或获取BufferedInputStream进行读取

相关推荐