3

我有循环来保存几个对象。在循环中调用服务方法并捕获异常。服务保存方法被注解为@Transactional,并且在内部进行休眠保存或更新调用。服务由 ApplicationContext 对象的 getBean 方法提供。我在循环之前只调用一次。

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

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

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

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

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

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

我正在使用 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 上

4

4 回答 4

10

关于您的问题,我有不同的建议。

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

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

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

建议2:你在hibernate 4中遇到了一个错误

hibernate JIRA 在这方面有一些错误报告。(没有您的代码,很难说出您的确切情况)。您的行为很有可能与这些错误之一有关:

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

这个错误有一些解决方法吗?

我有几个建议可以尝试:

将 hibernate.jdbc.batch_size 设置为 1 以上Michale Wyraz在此处提出了此解决方法,并且似乎有效。

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

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

降级到 hibernate 3.X:我再次说这不是一个解决方案,但它可能表明您确实面临 hibernate 4 中的错误。

升级到休眠 4.2+:正如其他答案中所建议的以及休眠基本代码的最新更改:只需升级休眠即可解决问题。

于 2013-02-10T10:46:28.010 回答
3

在尝试关闭 Session 时,我因类似的问题浪费了几个小时,不幸的是,ben75 的建议都没有奏效。这是我的环境:

  • 错误信息:org.hibernate.HibernateException: proxy handle is no longer valid ...
  • 休眠版本4.1.7
  • 应用服务器:IBM WebSphere 7

因此,以防其他人偶然发现此错误,对我有用的解决方案是升级到 Hibernate 4.2。所需的罐子是:

  • antlr-2.7.7.jar
  • dom4j-1.6.1.jar
  • hibernate-commons-annotations-4.0.1.Final.jar
  • hibernate-core-4.2.0.Final.jar
  • hibernate-jpa-2.0-api-1.0.1.Final.jar
  • javassist-3.15.0-GA.jar
  • jboss-logging-3.1.0.GA.jar
  • jboss-transaction-api_1.1_spec-1.0.0.Final.jar

HTH。

于 2013-03-27T14:45:41.927 回答
0

只是一个猜测。@Transactional通过回滚关闭异常事务。所以物体变得有点分离。

我会@Transactional从迭代要保存的对象的主要方法中删除,并使 @Transactional 成为仅保存对象的单独方法。

于 2013-01-31T09:01:12.687 回答
-1

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

于 2016-06-08T11:11:44.407 回答