业务系统在使用hibernate的list方法做查询时报了以下的一个错误:
org.hibernate.exception.DataException: Could not execute JDBC batch update,非常奇怪,我们当前的方法中并没有做更新操做和保存操作啊,怎么报了这样一个错误?于是顺着问题追了下去,主要是org.hibernate.impl.SessionImpl中的关键代码:
public List list(String query, QueryParameters queryParameters) throws HibernateException {
errorIfClosed();
checkTransactionSynchStatus();
queryParameters.validateParameters();
HQLQueryPlan plan = getHQLQueryPlan( query, false );
autoFlushIfRequired( plan.getQuerySpaces() );
List results = CollectionHelper.EMPTY_LIST;
boolean success = false;
dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
try {
results = plan.performList( queryParameters, this );
success = true;
}
finally {
dontFlushFromFind--;
afterOperation(success);
}
return results;
}
/**
* detect in-memory changes, determine if the changes are to tables
* named in the query and, if so, complete execution the flush
*/
protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
errorIfClosed();
if ( ! isTransactionInProgress() ) {
// do not auto-flush while outside a transaction
return false;
}
AutoFlushEvent event = new AutoFlushEvent(querySpaces, this);
AutoFlushEventListener[] autoFlushEventListener = listeners.getAutoFlushEventListeners();
for ( int i = 0; i < autoFlushEventListener.length; i++ ) {
autoFlushEventListener[i].onAutoFlush(event);
}
return event.isFlushRequired();
}
注意:第二个方法autoFlushIfRequired的注释意思是:在当前session中,如果发现有查询HQL涉及到的java对象在当前一级缓存中是游离状态,则会将其flush进数据库,如果在flush批处理的过程中出现问题,则会抛上边batch update的异常。这里要提到的是:如果是SQL查询就不会有这个问题,因为hibernate现在不从SQL倒推出SQL里表对应的java持久化对象,因此不会执行flush操作。 总结一句话:使用开源工具,有刁钻问题网上查不到就直接进源码,很多源码里都有明确清晰的注释,让人恍然大悟。以上说的可能不够全面,算是抛砖引玉了。