在oracle中,用hibernate操作clob对象花了三天时间。终于把他弄对了。
前提:oracle中用一个clob字段。hbm.xml中对应的是java.sql.Clob/
<property name="answer" type="java.sql.Clob" update="true" insert="true" column="answer" />
pojo中:
....... 其他属性 private java.sql.Clob; public Clob getAnswer() { return this.answer; } public void setAnswer(Clob answer) { this.answer = answer; } .........其他方法
存储的时候用session.save(obj)的方法;
这样做 clob属性中数据少的时候没报错。但数据量大的时候就会抛莫名其妙的异常。
问题出在Oracce中Blob/Clob字段独特的访问方式,Oracle Blob/Clob字段本身拥有一个游标(cursor) , JDBC必须通过游标对Blob/ Clob字段进行操作,在Blob/Clob字段被创建之前,我们无法获取其游标句柄,这也就意味着,我们必须首先创建一个空Blob/Clob字段,再从这个空Blob/Clob字段获取游标,写入我们所期望保存的数据。
至于如何操作可参考本博客其他文章(转载的)。
这里主要讲述两个异常
(1) java.lang.ClassCastException : org.hibernate.lob.clobImpl 转型异常
原因:用hibernateTemplate.save(),或者session.save()保存完对象后发现其对象的类型是clobImpl的。
此时强制转化就会报错。
解决方法:要用session.refresh()方法。也就是说refresh()方法必须在取clob对象之前。
(2) ORA-01002: 读取违反顺序
原因:在refresh方法的时候导致的
解决方法:用session开始一个事务。然后就最后末事务在提交。(至于为什么,我也不清楚)
上述主要涉及的是hibernate存储clob,若直接用jdbc同样注意两个错误。
(1)ORA-01002: 读取违反顺序
同上原理。设置connection 自动提交为false,
conn.setAutoCommit(false);
(2)ORA-22920: 未锁定含有 LOB 值的行
在select 时候 要加上 “for update ”
例子:
Connection conn = getConnection(); conn.setAutoCommit(false); PreparedStatement p=conn.prepareStatement("select * from train_test where id='"+po.getId()+"' for update"); ResultSet rs = p.executeQuery(); rs.next(); CLOB testDesc= (CLOB) rs.getClob("test_desc"); CLOB answer= (CLOB) rs.getClob("answer"); testDesc.putString(1, getValue(ret,"试题题目")); answer.putString(1, getValue(ret,"试题答案")); p=conn.prepareStatement("update train_test set test_desc=? ,answer=?"); p.setClob(1, testDesc); p.setClob(2, answer); p.executeUpdate(); conn.commit();
写完,收工。