Hibernate 中Blob字段的使用
create table textblob (tid number(38,0),lob blob)
然后建立对应的Java对象
public class testblob {
private long id;
private byte[] lob;
//set和get方法略...
}最后是Hibernate配置和映射文件。
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">
oracle.jdbc.driver.OracleDriver
</property>
<property name="connection.url">
jdbc:oracle:thin:@xxx.xxx.xxx.xxx:1521:orcl
</property>
<property name="connection.useUnicode">true</property>
<property name="connection.characterEncoding">UTF-8</property>
<property name="connection.username">xxxxxx</property>
<property name="connection.password">xxxxxx</property>
<property name="hibernate.connection.provider_class">
org.hibernate.connection.C3P0ConnectionProvider
</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.timeout">120</property>
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">120</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.connection.SetBigStringTryClob">
true
</property>
<property name="hibernate.jdbc.use_streams_for_binary">
true
</property>
<property name="dialect">
org.hibernate.dialect.Oracle9Dialect
</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</property>
<mapping resource="org/Miao/testblob.hbm.xml" />
</session-factory>
</hibernate-configuration>
注意配置文件中“hibernate.jdbc.use_streams_for_binary”这个部分。这是Oracle必须添加的属性。其它配置没有什么特别的。SQL Server不需要这个属性。同时配置文件配置了一个C3P0数据库连接池。
映射文件如下:
<hibernate-mapping package="org.Miao">
<class name="testblob" table="tblob">
<id name="id" column="tid">
<generator class="native"></generator>
</id>
<property name="lob" column="tlob" type="binary">
</property>
</class>
</hibernate-mapping>
然后就可以测试一下了。写一个运行的测试类Run.class。
public class run {
public static void main(String[] args) {
Configuration configuration = new Configuration();
configuration.configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
File f = new File("d:/f.exe");
byte[] tmp = new byte[(int) f.length()];
try {
FileInputStream fi = new FileInputStream(f);
fi.read(tmp);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
testblob test = new testblob();
test.setId(5);
test.setLob(tmp);
Transaction t = session.beginTransaction();
try {
session.saveOrUpdate(test);
t.commit();
} catch (HibernateException e) {
e.printStackTrace();
t.rollback();
} finally {
session.close();
}
}
}
现在进入数据库的话,可以看到数据库记录中已经增加了一条,文件已经被保存到数据库里了。但是,这么做有一个很大的问题,那就是内存。在Eclipse+WTP的环境下,加入的文件稍微大一点,就会造成OutofMemony异常。因为用这种方法存入数据库,需要把文件全部读入内存才可以。文件一大,就会造成内存溢出,即使把JVM使用的内存调大,保存大文件也是非常慢的。我的调试环境,存一个10M的文件,单用户Tomcat(内存调整到256-512M)跑,Oracle10g又是远程,需要好几分钟。多用户条件下,性能可想而知。而且,一旦多用户同时保存或同时读取大文件,立马会造成内存占用暴增,最后溢出。所以,使用这种方式处理Blob,一定要注意,不要保存大文件,我觉得最好不要超过1M。
评论
Hibernate2到Hibernate3可以说是一个飞跃。所以不要把Hibernate2的实践直接套用在3上。请在写代码的时候,自己先在机器上运行一下。
把你的实现修改一下.
<property name="lob" column="tlob" type="java.sql.Blob">
然后要在hibernate配置文件中加入一句话:
<property name="hibernate.jdbc.batch_size">0</property>
因为Oracle JBDC不允许流操作以批量方式执行.
然后
测试类里面可以写:
testblob test = new testblob();
test.setId(5);
test.setLob(Hibernate.createBlob(new byte[1]));
Transaction t = session.beginTransaction();
session.save(test);
//调用flush方法,强制Hibernate立即执行 sql 语句
session.flush();
//通过refresh方法,强制Hibernate执行select for update
session.refresh(test,LockMode.UPGRADE);
//向Blob写入实际内容
oracle.sql.BLOB blob=(oracle.sql.BLOB)test.getLob();
OutPutStream out =blob.getBinaryOutputStream();
FileInputStream imgis=new FileInputStream("xx.jpg");
byte[] buf = new byte[10240];//10k缓存
int len=0;
while((len=imgis.read(buf))>0){
out.write(buf,0,len);
}
imgis.close();
out.close();
session.save(test);
t.comit();
很可惜。这么写是错误的。
Hibernate.createBlob(new byte[1]))生成的BLOB根本无法转化成Oracle的BLOB。它们虽然都继承自BLOB,但是不能强行转换。这种写法只适用于Hibernate2,3以后是不能用的。如果不想用我的方法,那么只能自己写Hibernate类型或使用Spring提供的类型。但是这样一来增加了难度或和Spring紧耦合了。
还有,你的写法造成了代码和数据库的紧耦合。也就是说如果更换数据库,那么必须修改代码。同时在Hibernate配置中关闭了批处理,造成系统整个性能下降。可以说是得不偿失。
深入浅出Hibernate我记得应该是一本比较早期的Hibernate参考书,上面的很多东西已经不适用于最新的Hibernate版本了。
把你的实现修改一下.
<property name="lob" column="tlob" type="java.sql.Blob">
然后要在hibernate配置文件中加入一句话:
<property name="hibernate.jdbc.batch_size">0</property>
因为Oracle JBDC不允许流操作以批量方式执行.
然后
测试类里面可以写:
testblob test = new testblob();
test.setId(5);
test.setLob(Hibernate.createBlob(new byte[1]));
Transaction t = session.beginTransaction();
session.save(test);
//调用flush方法,强制Hibernate立即执行 sql 语句
session.flush();
//通过refresh方法,强制Hibernate执行select for update
session.refresh(test,LockMode.UPGRADE);
//向Blob写入实际内容
oracle.sql.BLOB blob=(oracle.sql.BLOB)test.getLob();
OutPutStream out =blob.getBinaryOutputStream();
FileInputStream imgis=new FileInputStream("xx.jpg");
byte[] buf = new byte[10240];//10k缓存
int len=0;
while((len=imgis.read(buf))>0){
out.write(buf,0,len);
}
imgis.close();
out.close();
session.save(test);
t.comit();
但是我没找到Hibernate直接映射能这么做的方法。能否给个例子?
Hibernate对JDBC做了很多封装。所以我们从Hibernate得到的CLOB和BLOB其实都是Hibernate自己实现的。而像Oracle之类的一些数据库,他们如果要操作BLOB、CLOB,需要用他们自己实现的对象。而Hibernate中得到的大字段对象是无法转化成数据库特有的大字段对象的。如果非要这么做,只能单独写纯JDBC。那么JDBC的获得、代码耦合、事务难以控制等问题都来了。
至于缓冲,我不知道数据库驱动保存BLOB能否自动缓冲。但是,缺省情况下,是要先把整个文件都读到内存中的。这个可无法缓冲。所以,如果一个人读入一个10M的文件,那么这10M在存入数据库前,都要保留在内存中,100个人的话,就要1G。如果更大,那么内存需要更是恐怖。
"直接把大量文字写入字段中而不用进行复杂编码"
"所以,使用这种方式处理Blob,一定要注意,不要保存大文件,我觉得最好不要超过1M。"
似乎这个方案还有待斟酌?
是否可以 buffer byte[]
发表评论
提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则
- 浏览: 19281 次

- 详细资料
搜索本博客
最新评论
-
配置Glassfish多机集群 ...
robbin 写道dinghyana 写道多机是集群,单机上的多个实例又叫啥? ...
-- by Joo -
配置Glassfish多机集群 ...
大哥,我还有疑问, "如果你觉得这么访问不方便,一会儿103一会儿104的,你可 ...
-- by dinghyana -
配置Glassfish多机集群 ...
请问 如何验证 LoadBalance 呢? 我初步是这样做,您看对不对? 我在 ...
-- by dinghyana -
配置Glassfish多机集群 ...
dinghyana 写道多机是集群,单机上的多个实例又叫啥?前者叫做水平群集,后 ...
-- by robbin -
配置Glassfish多机集群 ...
多机是集群,单机上的多个实例又叫啥?
-- by dinghyana






评论排行榜