Java HibernateeException:发生数据库冲突错误后,代理句柄不再有效

Java HibernateeException:发生数据库冲突错误后,代理句柄不再有效,java,spring,hibernate,Java,Spring,Hibernate,我有一个循环来保存两个对象。在循环中调用服务方法并捕获异常。服务保存方法被注释为@Transactional,内部执行hibernate saveOrUpdate调用。 服务由ApplicationContext对象的getBean方法提供。在循环之前我只调用它一次 在循环中,捕获oracle约束冲突异常后: org.hibernate.exception.constraintviolationexception:ora-00001:违反了唯一约束(ccb.sys_c0017085) 我记录问题

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

在循环中,捕获oracle约束冲突异常后:

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

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

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

有时,它只在每个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上,只是猜测而已
@Transactional
通过回滚关闭异常时的事务。所以物体变得有点分离


我将从您迭代要保存的对象的主方法中删除
@Transactional
,并使@Transactional成为仅保存对象的分离方法。

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

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

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

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

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

HibernateJira中有一些关于此区域的错误报告。(如果没有您的代码,很难说出您的确切情况)。您的行为很有可能与以下错误之一有关:

(这个和你的很接近,但还有一些其他的)

这个错误有解决方法吗

我有几点建议可以尝试:

将hibernate.jdbc.batch\u大小设置为大于1的值。这一解决办法是由Michale Wyraz提出的,似乎有效

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

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

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


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

我在尝试关闭会话时因类似问题损失了数小时,不幸的是,ben75的建议都不起作用。这就是我的环境:

  • 错误消息:
    org.hibernate.HibernateException:代理句柄不再有效…
  • 休眠版本4.1.7
  • 应用服务器:IBM WebSphere 7
所以,为了防止其他人偶然发现这个错误,对我有效的解决方案是升级到Hibernate4.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.

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

我提供了一些代码。我想我完全按照你的建议去做,不是吗?我是说,我以前是这样用的。没有成功。你能发布完整的stacktrace吗?为什么要使用反射?您只需调用
service.saveRecord(实体,“testUser”)
I为文件中给出的保存记录准备通用解决方案。服务级别和实体