我有循环来保存几个对象。在循环中调用服务方法并捕获异常。服务保存方法注释@Transactional,内部执行hibernate saveOrUpdate调用。 服务由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
上答案 0 :(得分:10)
我对您的问题有不同的建议。
建议1 :您错误地在所有交易中重复使用同一会话。
要检查这一点:在saveRecord
中放置一个断点,并检查两次连续呼叫中对SessionImpl
的引用是否有所不同。
老实说,这是您的问题的可能性很小,因为您的代码与MS SQL Server一起运行。因此,这个建议正确的唯一机会是MS SQL Server中的约束与Oracle中的约束不同。另外,我认为在这种情况下,hibernate会抛出一个更明确的异常。
建议2 :您正在遇到hibernate 4中的错误
这个领域的hibernate JIRA中有一些bug报告。 (没有你的代码,很难说出你的具体情况)。您的行为很可能与其中一个错误相关联:
https://hibernate.onjira.com/browse/HHH-7688(这个与你的非常接近,但还有其他一些)
这个bug有一些解决方法吗?
我几乎没有尝试过的建议:
将hibernate.jdbc.batch_size设置为高于1 的值。 Michale Wyraz建议here这种解决方法似乎有效。
不要使用反射:不确定它会有所帮助,但是事务是由aop-proxy处理的,并且使用反射可能会导致绕过某些事务管理器代码(它不应该,但这是一个检查的假设。
更改连接发布模式:所有这些错误(在hibernate JIRA中)或多或少与JdbcConnection管理相关,因此更改connection release mode可能会在somepoint帮助您识别问题。 (我不是说改变它是解决方案,如果你真的遇到了hibernate中的一个bug:你最好的选择可能是等待/贡献修复)
降级为休眠3.X :我不再说它是一个解决方案,但它可能表明你真的遇到了hibernate 4中的一个错误。
升级到hibernate 4.2 + :正如其他答案和hibernate基本代码中最近的更改所建议的那样:只需升级hibernate就可以解决问题。
答案 1 :(得分:3)
我在尝试关闭Session时遇到了类似问题,但很遗憾没有ben75的建议有效。这是我的环境:
org.hibernate.HibernateException: proxy handle is no longer valid ...
所以只是在其他人偶然发现这个错误的情况下,对我有用的解决方案是升级到Hibernate 4.2。必需的罐子是:
HTH。
答案 2 :(得分:0)
只是一个猜测。 @Transactional
通过回滚关闭Exception上的事务。所以对象变得有点脱离。
我会从主要方法中删除@Transactional
,在那里迭代要保存的对象,并使@Transactional成为只保存对象的separet方法。
答案 3 :(得分:-1)
如果批处理语句抛出异常(在org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch()中),Hibernate 4.1.3不会关闭它们。 你捕获异常,回滚当前事务,开始一个新事务并希望一切都很完美。 但是如果您运行本机更新脚本(例如),则在运行之后,最终要关闭语句。在这里,未闭合(由于回滚而现在已分离)语句抛出此异常并且您的新事务出错。幸运的是,在新的异常之前,语句被清除了,所以只有第一次更新出错... 我创建了一个处理程序方法,我在每次回滚时调用它(这种情况它在初始异常后被调用),并且在回滚后开始我创建一个虚拟(和快速)更新(update [tablename] set [column] = [column ]其中1 = 2)并执行它。它触发上面的错误,我抓住它,再次回滚事务并创建一个新的,所以我退出方法与一个良好的休眠会话和一个生活事务。 这是一个丑陋的解决方法,但我现在无法升级hibernate版本......