最近在做一个博客,里面的content字段本来是使用varchar2(4000),但是实际使用发现最多只能存入600多个字符,很奇怪,具体原因还不知道。在同事建议下决定使用clob来存储大文本;
在网上查阅了一些资料,其中一种方法是:
在hbm文件中加
- <property name="content" type="text">
- <column name="CONTENT" length="100000" />
- property>
在.java中把content字段设为String类型,就可以把clob当作varchar来操作,但是存储时就出错
streams type cannot be used in batching
之后修改ssessionfactory
- <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
- <property name="dataSource" ref="dataSource" />
- <property name="configLocations">
- <list>
- <value>classpath:config/application.cfg.xmlvalue>
- <value>classpath:config/basecommon.cfg.xmlvalue>
- <value>classpath:config/parameter.cfg.xmlvalue>
- list>
- property>
- <property name="hibernateProperties">
- <props>
- <prop key="hibernate.dialect">....prop>
- <prop key="hibernate.show_sql">trueprop>
- <prop key="hibernate.format_sql">trueprop>
- <prop key="hibernate.jdbc.batch_size">0prop>
- props>
- property>
- bean>
把batch_size设为0,之后存储很小的文本时可以正常了,但是文本一大起来,就出错
Connection reset SQL Error: 17002, SQLState: null
上网查,得知Oracle BLOB/CLOB 字段本身拥有一个游标(cursor),JDBC通过游标对Blob/Clob字段进行操作,在Blob/Clob字段创建之前,无法获取其游标句柄,会出现
Connection reset by peer: socket write error 异常。
正确的做法是:首先创建一个空 Blob/Clob 字段,再从这个空 Blob/Clob字段获取游标。
觉得和我的错误应该差不多,于是改写代码:
- <property name="contentClob" type="clob">
- <column name="CONTENT" length="100000" />
- property>
- blog.java中
- ......
- private Clob contentClob;
- private String content
- ......
- action中
- Session ssesion = persistence.getHibernateSession();
- Transaction ts = ssesion.beginTransaction();
- .......
- blog.setAuthor(author);
- blog.setContent(Hibernate.createcontentClob(" "));
- blog.setTitle(title);
- ssesion.save(blog);
- ssesion.flush();
- ssesion.refresh(blog,LockMode.UPGRADE);
- CLOB clob = (CLOB)blog.getcontentClob();
- Writer wt=Clob.getCharacterOutputStream();
- String content = blog.getContent();
- wt.write(content);
- wt.close();
- .......
这样的话,会抛出类型classCast的异常,在javaeye上看了robbin的一个帖子,中间lovehibernate说了一个解决方法:
使用hibernate.lob.SerializableClob来帮助类型转换;
把CLOB clob=(CLOB)blog.getcontentClob();换为
- SerializableClob clob=(SerializableClob)informationContent.getContent();
- java.sql.Clob wrapClob = clob.getWrappedClob();
- CLOB tmpClob=(CLOB)wrapClob;
- Writer wt=tmpClob.getCharacterOutputStream();
问题基本解决,可以正常插入了。
update的代码基本上相同:
- Session ssesion = persistence.getHibernateSession();
- Transaction ts = ssesion.beginTransaction();
- Blog blog = (Blog)ssesion.load(Blog.class,this.blog.getId(),LockMode.UPGRADE);
- ......
- blog.setContent(this.blog.getContent());
- blog.setContentClob(Hibernate.createClob(" "));
- ......
- ssesion.update(blog);
- ssesion.flush();
- ssesion.refresh(blog, LockMode.UPGRADE);
- SerializableClob clob = (SerializableClob) blog.getContentClob();
- java.sql.Clob wrapClob = clob.getWrappedClob();
- CLOB tmpClob = (CLOB) wrapClob;
- Writer wt = tmpClob.getCharacterOutputStream();
- String content = blog.getContent();
- wt.write(content);
如果不使用第3行那句,会报:未锁定含有 LOB 值的行 的异常.
如果不使用第6行那句,结果给字段添加内容的时候可以update成功,但是删除字段内容的时候则不会有任何效果
后来数据库改用oralce10g,发现在jdbc的包中,getCharacterOutputStream()方法都被deprecated了,于是修改为:
- Writer wt = tmpClob.setCharacterStream(0);