Hibernate抛出SQLException无法重置读者

时间:2011-10-03 11:56:20

标签: hibernate

java.sql.SQLException: could not reset reader
        at org.hibernate.lob.ClobImpl.getCharacterStream(ClobImpl.java:100)
        at org.hibernate.type.ClobType.set(ClobType.java:70)
        at org.hibernate.type.ClobType.nullSafeSet(ClobType.java:141)
        at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2025)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2271)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2688)
        at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)

您好,

以上是堆栈跟踪。 它正在处理少量数据,但因大数据而失败。 我无法弄清楚可能是什么问题?

此致 普里特

2 个答案:

答案 0 :(得分:3)

我们刚刚解决了类似的问题,我想在这里描述问题以防有人遇到它。请注意,another question存在同样的问题。我们有Oracle 10,Hibernate 3,Java 1.4和修补Ojdbc14。我们使用Hibernate.createClob(String)创建了CLOB。程序(批处理作业)在大字符串(~700KB)上失败。

问题在于,使用Hibernate,我们首先使用CLOB插入实体并更新它(包括CLOB)。第二次更新是多对一更新的一部分。 CLOB之间没有变化,只是Hibernate想要更新它两次。它得到了“无法重置”的读卡器错误。似乎它不能两次使用相同的流。我们通过确保CLOB只保存一次来修复此问题。

答案 1 :(得分:0)

在将MySQL支持的事务系统移植到H2数据库时,我们遇到了这个问题。 (有点类似于现在已经过时的Hibernate论坛上的this issue。)

我们的故事

  1. 我们有带有blob字段的模型实体。
  2. 在代码中,我们以事务方式获取这些实体的批处理,将其状态更新为“处理中”,然后读取事务外部的Blob有效负载(在提交状态更新后)以进行实际处理。
  3. 最初,延迟加载无法正常工作,因此每次抓取都会将blob字段内容与实体一起拉入。

在事务提交时,Hibernate检查每个字段的脏污程度,并将所有脏字段的更新推送回数据库。

在Hibernate的变更检测机制中,始终将blob视为脏污(可能是因为您不能以非侵入方式比较两个blob;例如,如果一个blob被支持流,则您实际上必须按顺序使用该流)以便将其内容与另一个Blob进行比较。

退房:

  • org.hibernate.type.AbstractStandardBasicType#isDirty(java.lang.Object, java.lang.Object, boolean[], org.hibernate.engine.spi.SharedSessionContractImplementor)
  • org.hibernate.type.descriptor.java.BlobTypeDescriptor#areEqual

查看blob比较最终如何归结为简单的==检查。

虽然您可能希望它仍然返回true(因为我们从未接触过blob字段),但是代理包装和其他Hibernate级内部结构会导致最终的blob对象完全是另一个对象,导致{{1}失败}测试。

结果...

  1. 在提交阶段,每个先前获取的blob都被消耗(读取),以便将其内容写回到数据库中。

对于MySQL来说这不是问题,因为它们的Blob在内存中(并且可以多次读取而不会引起流耗尽)。但是H2提供了流支持的Blob,这意味着它们是一次读取的。

  1. 因此,当我们尝试在事务处理之后(重新)读取blob时,Hibernate试图将已消耗的流重置为下一次读取,但失败了。

我们的解决方案

解决方案只是启用{blob字段的延迟加载” (如this SO answer中所述。