|
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
|---|---|
| 作者 | 正文 |
|
时间:2008-01-21
猫咪以前发了一个关于在Hibernate中使用Clob字段的文章。可以做到以String的方式,直接把大量文字写入字段中而不用进行复杂编码。现在猫咪把使用Blob的方法也写出来。猫咪很懒,所以很久没有更新博客了。大家多多包涵! 下面是猫咪的例子(仍然使用Oracle,请确保使用最新的JDBC驱动) 首先建立一个数据库表 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。 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
时间:2008-01-21
不知道lz 有没有感觉
"直接把大量文字写入字段中而不用进行复杂编码" "所以,使用这种方式处理Blob,一定要注意,不要保存大文件,我觉得最好不要超过1M。" 似乎这个方案还有待斟酌? 是否可以 buffer byte[] |
|
| 返回顶楼 | |
|
时间:2008-01-21
我觉得无论如何,都最好不要往BLOB中存放大文件。毕竟从数据库中读大文件,是非常缓慢的(想想几百兆的文件从数据库一点一点都到服务器,然后再一点一点response出去)。我觉得大文件还是以文件的方式存放比较好。而且传输的时候,直接给出链接就够了。剩下的事情,由操作系统自己往网卡发就是了。可以大大减轻压力。
Hibernate对JDBC做了很多封装。所以我们从Hibernate得到的CLOB和BLOB其实都是Hibernate自己实现的。而像Oracle之类的一些数据库,他们如果要操作BLOB、CLOB,需要用他们自己实现的对象。而Hibernate中得到的大字段对象是无法转化成数据库特有的大字段对象的。如果非要这么做,只能单独写纯JDBC。那么JDBC的获得、代码耦合、事务难以控制等问题都来了。 至于缓冲,我不知道数据库驱动保存BLOB能否自动缓冲。但是,缺省情况下,是要先把整个文件都读到内存中的。这个可无法缓冲。所以,如果一个人读入一个10M的文件,那么这10M在存入数据库前,都要保留在内存中,100个人的话,就要1G。如果更大,那么内存需要更是恐怖。 |
|
| 返回顶楼 | |
|
时间:2008-01-22
blob可以放到InputStream,需要时再去读
|
|
| 返回顶楼 | |
|
时间:2008-01-22
rainy 写道 blob可以放到InputStream,需要时再去读
但是我没找到Hibernate直接映射能这么做的方法。能否给个例子? |
|
| 返回顶楼 | |
|
时间:2008-02-02
根据深入浅出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();
|
|
| 返回顶楼 | |
|
时间:2008-02-02
dmewy 写道 根据深入浅出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.createBlob(new byte[1]))生成的BLOB根本无法转化成Oracle的BLOB。它们虽然都继承自BLOB,但是不能强行转换。这种写法只适用于Hibernate2,3以后是不能用的。如果不想用我的方法,那么只能自己写Hibernate类型或使用Spring提供的类型。但是这样一来增加了难度或和Spring紧耦合了。 还有,你的写法造成了代码和数据库的紧耦合。也就是说如果更换数据库,那么必须修改代码。同时在Hibernate配置中关闭了批处理,造成系统整个性能下降。可以说是得不偿失。 深入浅出Hibernate我记得应该是一本比较早期的Hibernate参考书,上面的很多东西已经不适用于最新的Hibernate版本了。 |
|
| 返回顶楼 | |
|
时间:2008-02-02
我去卓越网看了一下你说的那本书的介绍。在章节目录中有“移植到Hibernate 3 ”这么一章。虽然在简介里没有说明介绍的Hibernate的版本,但是通过这章,可以很明显看出介绍的是Hibernate2。
Hibernate2到Hibernate3可以说是一个飞跃。所以不要把Hibernate2的实践直接套用在3上。请在写代码的时候,自己先在机器上运行一下。 |
|
| 返回顶楼 | |
浏览 1068 次






