blob字段采用单字节存储,适合保存二进制数据,如图片文件;Clob字段采用多字节存储,适合保存大型文本数据。
在SQL Server中,Blob和Clob分别对应image和ntext
先在TUser表中新增两个字段image类型的image,ntext类型的resume
TUser.hbm.xml增加两个属性/字段映射
<property name="image" column="image" type="java.sql.Blob"/>
<property name="resume" column="resume" type="java.sql.Clob"/>
TUser.java增加两个域
private Blob image; private Clob resume;
OK, 可以这样来存
TUser user = new TUser();
user.setName("earth");
user.setImage(Hibernate.createBlob(new FileInputStream("C:\\myimage.jpg")));
user.setResume(Hibernate.createClob("This is a clob"));
session.save(user);
Hibernate为我们提供了一序列生成LOB字段的静态方法:
public static Blob createBlob(byte[] bytes)
public static Blob createBlob(InputStream stream, int length)
public static Blob createBlob(InputStream stream)
public static Clob createClob(String string)
public static Clob createClob(Reader reader, int length)
对应的读取操作如下:
TUser user = (TUser)session.load(TUser.class, new Integer(id));
Blob image = resume.getImage();
// ---
InputStream is = image.getBinaryStream();
FileOutputStream fos = new FileOutputStream("C:\\outImg.jpg");
byte[] buf = new byte[102400];
int len;
while((len = is.read(buf)) != -1){
fos.write(buf,0,len);
}
fos.close();
is.close();
// --
Clob resume = user.getResume();
System.out.println(resume.getSubString(1,(int)resume.length()));
SQL Server下Blob, Clob的读写都非常简单,Oracle相对复杂!
Hibernate下修改数据库很简单,在hibernate.cfg.xml中切换一下Dialect,再次运行上面的代码
错误1:streams type cannot be used in batching.
解决,<property name="hibernate.jdbc.batch_size">0</property>
错误2:Connnection reset by peer: socket write error.
解决:Oracle中的Blob/Clob字段本身拥有一个游标,JDBC必须通过游标对Lob字段进行操作,在Lob字段创建之前,我们无法获取其游标句柄,所以要先创建一个空的Lob字段以先获得操作Lob字段的句柄,晕!
在一般的JDBC中,对Oracle Lob字段的写分三步:
STEP 1: insert into(image,resume)values(?,?);
pstmt.setBlob(index,oracle.sql.BLOB.empty_lob())
pstmt.setClob(index,oracle.sql.CLOB.empty_lob())
pstmt.executeUpdate();
STEP2: select image,resusme from... for update
注意!!!必须加for update,这将锁定该行,直至该行被修改完毕,保证不产生并发冲突。
java.sql.ResultSet rs = pstmt.executeQuery();
weblogic.jdbc.vendor.oracle.OracleResultSet
//获得Lob字段的操作句柄
oracle.sql.BLOB image = (oracle.sql.BLOB)rs.getBlob(1);
oracle.sql.CLOB resume =(oracel.sql.CLOB)rs.getClob(2);
weblogic.jdbc.vendor.oracle.OracleThinBlob
weblogic.jdbc.vendor.oracle.OracleThinClob
//将文本写入Clob
resume.putString(1,"This is my clob");
//将图片写入Blob,不是直接对image操作,而是先获得它的一个OutputStream
FileInputStream fis = new FileInputStream("C:\\inputImg.jpg");
OutputStream imageStream = image.getBinaryOutputStream();
byte[] buf = new byte[10240]; //10K缓存
int len;
while((len=fis.read(buf))>0){
imageStream.write(buf,0,len);
}
fis.close();
imageStream.close();
STEP3: update .. set image=?, resume=?
pstmt.setBlob(1,image);
pstmt.setClob(2,resume);
pstmt.executeUpdate();
在Hibernate中,相应的实现过程如下!
STEP 1:
TUser user = new TUser();
user.setName("Earth");
user.setImage(Hibernate.createBlob(new byte[1]));
user.setResume(Hibernate.createClob(" "));
Transaction tx = session.beginTransaction();
session.save(user);
session.flush();//强制Hibernate立即执行insert操作
STEP 2:
//强制Hibernate执行select for update
session.refresh(user, LockMode.UPGRADE);
//获得Lob字段的操作句柄
oracle.sql.BLOB image = (oracle.sql.BLOB)user.getImage();
oracle.sql.CLOB resume =(oracel.sql.CLOB)user.getResume();
//将文本写入Clob
java.io.Writer writer = resume.getCharacterOutputStream();
writer.writer("this is my resume");
writer.close();
//将图片写入Blob,不是直接对image操作,而是先获得它的一个OutputStream
同一般的JDBC
STEP 3:
session.save(user);
tx.commit();
读操作同SQL SERVER 一样
Hibernate通过Session.save/flush/refresh方法的组合使用,实现了上面JDBC代码中的lob访问逻辑
要注意的是:Oracle Thin Driver对Clob字段支持尚有欠缺,Clob字段超出4000字将无法读取
另外要注意的是:
java.sql.Blob
oracle.sql.BLOB
注意看blob的大小写,是不一样的。写程序的时候不要搞混了
参考:http://hi.baidu.com/lylianyu/blog/item/e87e980968b5fb2d6a60fb24.html