Java大对象类型的Hibernate映射

本文介绍如何使用Java和Hibernate处理Oracle数据库中的Blob和Clob数据类型,包括创建空Blob/Clob对象、通过流机制写入数据及事务处理等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  
Java中,java.lang.String可用于表示长字符串(长度超过255),字节数组byte[]可以用于存放图片户或文件二进制数据。此外,在JDBC API中还提供了java.sql.CLOBjava.sql.BLOB类型,他们分别表示标准SQL中的CLOB(字符大对象)和BLOB(二进制大对象)类型。表2.4列出了Java大对象,Hibernate映射类型以及标准SQL的对应关系。
2.4
 
 
 
 
映射类型
Java类型
标准SQL类型
binary
byte[]
VARBINARY(或者BLOB)
text
java.lang.String
CLOB
serilizable
实现java.io.Serializable的任何一个Java
VARBINARY(或者BLOB)
clob
java.sql.CLOB
CLOB
blob
java.sql.BLOB
BLOB
注意:不允许用表2.4中列出的数据类型来定义持久化类的OID
2)、BLOB,CLOB数据的处理(以Oracle数据库为例):
 假设我们有如下表
 
T_User 
id     number   <pk>
name varchar2(50)
age    number
image    BLOB
resume   CLOB          
 对应的映射文件如下:
<hibernate-mapping>
 <class name=”com.neusoft.hibernate.db.entity.TUser” table=”T_User”>
<id name=”id” column=”id” type=”java.lang.Integer”>
 <generator class=”native”/>
</id>
<property name=”name” type=”java.lang.String” column=”name”/>
<property name=”age” type=”java.lang.Integer” column=”age”/>
<property name=”image” type=”java.sql.Blob” column=”image”/>
<property name=”resume” type=”java.sql.Clob” column=”resume”/>
 </class>
</hibernate-mapping>
实体类如下:
public class Tuser implements Serializable{
 private Integer id;
 private String name;
 private Integer age;
 private Blob image;
 private Clob resume;
 …getter/setter…..
}
BLOBCLOB这种大对象一般都是采用流机制作为数据读取方式,所以这种读取方式在Oracle这种自视为数据库中贵族的数据库中对这种操作就会有诸多的限制,有时候会叫人觉得不太友好(这是典型的店大欺客)
限制一:Oracle JDBC不允许流操作以批量方式执行,如果发生这种错误一般会抛出
ERROR JDBCExceptionReport:streams type cannot be used in batching.出现这种情况一般都需要将hibernate.cfg.xml中的hibernate.jdbc.batch_size设定为0即可消除,但是这就会影响其他的更新,插入,删除操作的性能,因此必须在一个数据库事务中对Clob,Blob进行操作,也只有在一个数据库事务中Clob,Blob对象才会有效。
限制二:Oalce Blob/Clob具有独特的访问方式,这种类型字段拥有一个游标(cursor)JDBC必须通过游标对Blob/Clob进行操作,在Blob/Clob创建之前我门无法获得其游标句炳,这就意味着必须首先创建一个空Blob/Clob字段,在丛空Blob/Clob获取游标,然后写入我们期望的数据。
 
首先看一下采用传统JDBC进行操作的代码:
//….获取Connection连接
conn.setAtuoCommit(false);
//插入Blob/Clob空值字段
PrepareStatement prestmt=conn.prepareStatement(“insert into T_USER(name,age,id,image,resume) values(?,?,?,?,?)”);
prestmt.setString(1,”zx”);
prestmt.setInt(2,26);
prestmt.setInt(3,5);
//通过oracle.sql.BLOB/CLOB.empty_lob()方法构造空Blob/Clob对象
prestmt.setBlob(4,oracle.sql.BLOB.empty_lob());
prestmt.setClob(5,oracle.sql.CLOB.empty_lob());
prestmt.executeUpdate();
prestmt.close();
//再次从数据库中获得Blob/Clob句炳
prestmt=conn.prepareStatement(“select image,resume from T_USER where id=? for update ”);
prestmt.setInt(1,5);
ResultSet rset=prestmt.executeQuery();
rset.next();
oracle.sql.BLOB imgBlob=(oracle.sql.BLOB)rset.getBlob();
oracle.sql.CLOB resClob=(oracle.sql.CLOB)rset.getClob();
//将二进制数据写入Blob
FlieInputStream fin=new FileInputStream(“c://image.jpg”);
OutputStream out=imgBlob.getBinaryOutputStream();
byte[] buf=new byte[fin.available()];
int len;
while((len=fin.read(buf))!=-1){
 out.write(buf,0,len);
}
fin.close();
out.close();
//将字符串写入Clob
resClob.putString(1,”This is my clob”);
//将更新写回数据库
prestmt=conn.prepareStatement(“update T_USER set image=?,resume=? where id=? ”);
prestmt.setBlob(1,imgBlob);
prestmt.setClob(2,resClob);
prestmt.setInt(3,5);
prestmt.executeUpdate();
prestmt.close();
conn.commit();
conn.close();
 
 
以上是传统的采用JDBC方式处理,注意他将连接的自动提交属性设置为false然后将所有的操作并入一个事务中,然后进行提交,这是处理OracleBlob/Clob字段的一般机制,所以Hibernate的处理就应该模仿JDBC的处理方式,因为从某种角度来讲Hibernate是对JDBC的封装因为它的底层访问机制仍然是基于JDBC的。
 
Hibernate的处理:
TUser user=new TUser();
user.setAge(new Integer(26));
user.setName(“zx”);
//创建空Blob/Clob对象
user.setImage(Hibernate.createBlob(new byte[1]));
user.setResume(Hibernate.createClob(“ “));//注意这里的参数是一个空格
Transaction tx=session.beginTransaction();
session.save(user);
//调用flush方法,强制Hibernate立即执行insert sql
session.flush();
//通过refresh方法,强制Hibernate执行select for update
session.refresh(user,LockMode.UPGRADE);
//Blob写入实际内容
oracle.sql.BLOB blob=(oracle.sql.BLOB)user.getImger();
OutputStream out=blob.getBinaryOutputStream();
FileInputStream fin=new FileInputStream(“c://image.jpg”);
byte[] buf=new byte[fin.available()];
int len;
while((len=fin.read())!=-1){
 out.write(buf,0,len);
}
fin.close();
out.close();
//Clob中写入数据
oracle.sql.CLOB clob=user.getResume();
java.io.Writer writer=clob.getCharacterOutputStream();
writer.write(“This is my resume!”);
writer.close();
session.saveOrUpdate(user);
session.commit();
tx.commit();
 
在实际应用中,对于Clob字段可以简单的将其映射为String类型,不过在Oracle Thin DriverClob字段支持上有欠缺,当Clob内容超过4000字节时将无法读取,而Oracle OCI Driver(需要在本地安装客户端组件)则可以完成大容量Clob字段操作。
 
对于上面的代码相信作为成熟的工程师来说都闻到一些bad smell,如果Blob/Clob字段普遍存在的话,那么我们的持久层逻辑可能遍布这种复杂的逻辑,不过不要着急在我即将讲解的客户自定义类中我们将会看到一个解决方案,通过自定义类型我们可以对数据类型的通用性进行抽象,对于Blob/Clob字段我们可以定义一种类型并以这种类型作为Blob/Clob字段的映射类型。(好了等到下一篇再说吧!)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值