HibernateException:数据库冲突错误后,代理句柄不再有效

我有循环来保存几个对象。 在循环中调用服务方法并捕获exception。 服务保存方法注释@Transactional,内部执行hibernate saveOrUpdate调用。 服务由ApplicationContext对象的getBean方法提供。 我在循环前只调用一次。

在循环中,在我捕获oracle约束违规的exception之后:

org.hibernate.exception.constraintviolationexception:ora-00001:违反了唯一约束(ccb.sys_c0017085)

我记录问题并尝试保存另一个对象。 我得到的下一个例外是:

org.hibernate.HibernateException:代理句柄不再有效

有时它在每次ora错误后只发生一次,但有时它会重复更多的对象(迭代)。

如何处理此exception以及如何使保存操作成为可能?

我正在使用Spring 3.1.3和Hibernate 4.1.7。

[编辑]一些代码示例:

@Service public class ServiceForRecord { @Transactional public Record saveRecord(Record record, String user) { Record obj = record; // some validation & seting internal values getHibernateTemplate().saveOrUpdate(obj) return obj; } ... 

在我的循环中我做:

 //in params: serviceClass = ServiceForRecord.class; entityClass = Record.class; saveMethod = "saveRecord"; //loop prepare service = getApplicationContext().getBean(serviceClass); serviceSave = serviceClass.getMethod("saveRecord", Record.class, String.class); while (condition) { entity = BeanUtils.instantiate(entityClass); //setup entity serviceSave.invoke(service, entity, "testUser"); //catch error } //end while 

[编辑]堆栈跟踪:

 PreparedStatementProxyHandler(AbstractProxyHandler).errorIfInvalid() line: 63 PreparedStatementProxyHandler(AbstractStatementProxyHandler).continueInvocation(Object, Method, Object[]) line: 100 PreparedStatementProxyHandler(AbstractProxyHandler).invoke(Object, Method, Object[]) line: 81 $Proxy100.clearBatch() line: not available NonBatchingBatch(AbstractBatchImpl).releaseStatements() line: 163 NonBatchingBatch(AbstractBatchImpl).execute() line: 152 JdbcCoordinatorImpl.getBatch(BatchKey) line: 151 SingleTableEntityPersister(AbstractEntityPersister).insert(Serializable, Object[], boolean[], int, String, Object, SessionImplementor) line: 2940 SingleTableEntityPersister(AbstractEntityPersister).insert(Serializable, Object[], Object, SessionImplementor) line: 3403 EntityInsertAction.execute() line: 88 ActionQueue.execute(Executable) line: 362 ActionQueue.executeActions(List) line: 354 ActionQueue.executeActions() line: 275 DefaultFlushEventListener(AbstractFlushingEventListener).performExecutions(EventSource) line: 326 DefaultFlushEventListener.onFlush(FlushEvent) line: 52 SessionImpl.flush() line: 1210 SessionImpl.managedFlush() line: 399 JdbcTransaction.beforeTransactionCommit() line: 101 JdbcTransaction(AbstractTransactionImpl).commit() line: 175 HibernateTransactionManager.doCommit(DefaultTransactionStatus) line: 480 HibernateTransactionManager(AbstractPlatformTransactionManager).processCommit(DefaultTransactionStatus) line: 754 HibernateTransactionManager(AbstractPlatformTransactionManager).commit(TransactionStatus) line: 723 TransactionInterceptor(TransactionAspectSupport).commitTransactionAfterReturning(TransactionAspectSupport$TransactionInfo) line: 392 TransactionInterceptor.invoke(MethodInvocation) line: 120 ReflectiveMethodInvocation.proceed() line: 172 AfterReturningAdviceInterceptor.invoke(MethodInvocation) line: 50 ReflectiveMethodInvocation.proceed() line: 172 JdkDynamicAopProxy.invoke(Object, Method, Object[]) line: 202 $Proxy71.save(Account, String) line: not available GeneratedMethodAccessor115.invoke(Object, Object[]) line: not available DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not available Method.invoke(Object, Object...) line: not available ImportServiceProvider.save(Object, String) line: 380 

[编辑]我注意到的最后一件事是它不会发生在MS SQL Server上,只发生在Oracle上

我对你的问题有不同的建议。

建议1 :您错误地在所有事务中重用相同的会话。

要检查这一点:在saveRecord放置一个断点,并检查在连续两次调用中对SessionImpl的引用是否不同。

老实说,这是您的问题的可能性很小,因为您的代码与MS SQL Server一起运行。 因此,这个建议正确的唯一机会是MS SQL Server中的约束与Oracle中的约束不同。 另外,我认为在这种情况下,hibernate会抛出一个更明确的exception。

建议2 :你正在遇到hibernate 4中的一个bug

在这个领域的hibernate JIRA中有一些bug报告。 (没有你的代码,很难说出你的确切情况)。 您的行为很可能与其中一个错误相关联:

https://hibernate.onjira.com/browse/HHH-7688 (这个非常接近你的,但还有一些其他的)

这个bug有一些解决方法吗?

我几乎没有尝试过的建议:

将hibernate.jdbc.batch_size设置为高于1的值 。 Michale Wyraz 在这里提出了这种解决方法,似乎有效。

不要使用reflection :不确定它会有帮助,但是事务由aop-proxy处理,并且使用reflection可能会导致绕过某些事务管理器代码(它不应该,但它是一个检查的假设)。

更改连接释放模式 :所有这些错误(在hibernateJIRA中) 或多或少与JdbcConnection管理相关,因此更改连接释放模式可能会在某些时候帮助您识别问题。 (我不是说改变它就是解决方案,如果你真的遇到了hibernate中的一个bug:你最好的选择可能是等待/贡献修复)

降级为hibernate3.X :我再一次不说它是一个解决方案,但它可能表明你真的遇到了hibernate 4中的一个bug。

升级到hibernate 4.2+ :正如其他答案所建议的那样,关于hibernate基本代码的最新变化:简单地升级hibernate可能会解决问题。

当我试图关闭Session时,我遇到了类似问题的小时数,不幸的是ben75的建议都没有。 这是我的环境:

  • 错误消息: org.hibernate.HibernateException: proxy handle is no longer valid ...
  • Hibernate版本4.1.7
  • 应用程序服务器: IBM WebSphere 7

所以只是在其他人偶然发现这个错误的情况下,对我有用的解决方案是升级到Hibernate 4.2。 必需的jar子是:

  • ANTLR-2.7.7.jar
  • dom4j的-1.6.1.jar
  • hibernate公地的注解,4.0.1.Final.jar
  • hibernate核心,4.2.0.Final.jar
  • 冬眠-JPA-2.0-API-1.0.1.Final.jar
  • Javassist进行-3.15.0-GA.jar
  • JBoss的日志记录,3.1.0.GA.jar
  • JBoss的事务,api_1.1_spec-1.0.0.Final.jar

HTH。

只是一个猜测。 @Transactional通过回滚关闭Exception上的事务。 所以对象变得有些脱节。

我会从main方法中删除@Transactional ,在那里迭代要保存的对象,并使@Transactional成为只保存对象的separet方法。

如果批处理语句抛出exception(在org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch()中),Hibernate 4.1.3不会关闭批处理语句。 你捕获exception,回滚当前事务,开始一个新事务并希望一切都很完美。 但是,如果您运行本机更新脚本(例如),则在运行之后,最终要关闭语句。 它来了,未闭合(现在由于回滚而分离)语句抛出此exception并且您的新事务出错。 幸运的是,在新的exception之前,语句被清除了,所以只有第一次更新出错…我创建了一个处理程序方法,我在每次回滚时调用它(这种情况在初始exception之后调用),并在回滚后开始我创建一个虚拟(和快速)更新(更新[tablename] set [column] = [column],其中1 = 2)并执行它。 它触发上面的错误,我抓住它,再次回滚事务并创建一个新的,所以我退出方法与一个良好的hibernate会话和一个生活事务。 这是一个丑陋的解决方法,但我现在无法升级hibernate版本…