I faced the same issue a while back, so in case it's useful, some observations on
why checkNamedQueries() is so slow on WebLogic.
First, some background: we have around 1600 named queries in our application. We support both WebLogic 8.1 SP4 and JBoss 4.0.3 RC1. The code base is pretty large, we have to bump the perm space up to 300M on WebLogic to avoid memory issues. On JBoss, checkNamedQueries() takes less than half a minute, while on WebLogic it takes around 5 1/2 minutes.
The following are the hibernate configuration properties we use:
Code:
hibernate.transaction.flush_before_completion=true
hibernate.connection.driver_class=net.sourceforge.jtds.jdbc.Driver
hibernate.cglib.use_reflection_optimizer=false
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.WeblogicTransactionManagerLookup
hibernate.dialect=org.hibernate.dialect.SQLServerDialect
hibernate.query.factory_class=org.hibernate.hql.classic.ClassicQueryTranslatorFactory
hibernate.cache.use_second_level_cache=false
hibernate.query.substitutions=true 1, false 0, yes 'Y', no 'N'
hibernate.jdbc.batch_size=0
hibernate.session_factory_name=eis.org.hibernate.SessionFactory
hibernate.connection.datasource=jdbc/TxSQLServer
hibernate.show_sql=false
hibernate.connection.provider_class=org.hibernate.connection.DatasourceConnectionProvider
hibernate.transaction.factory_class=org.hibernate.transaction.CMTTransactionFactory
My first patch was simply to comment out checkNamedQueries() from SessionFactoryImpl. However, I hadn't found this thread at that time and wasn't sure how safe it'd be, so I decided to delve a little deeper.
Using a debugger, I did find some interesting stuff; the following's an extract from a mail I sent to my team which explains the issue:
"First, for the upfront query compilation by Hibernate which takes up around half the startup time: slow classloading on WebLogic isn’t the main reason, it’s more of a combination of Hibernate issues and classloading. I was playing around with the debugger a bit, and I found that Hibernate calls Class.forName() or ClassLoader.loadClass() with class-names like ‘=’, ‘(‘, ‘)’, etc which obviously aren’t valid classes. What’s happening is this: while doing upfront compilation of named queries, Hibernate parses the queries into tokens and then tries to resolve many of the tokens (like ‘and’, ‘=’, ‘in’, etc) as Java classes for some reason. In the case of bad tokens, there’s a double overhead incurred before a ClassNotFoundException gets thrown: first ClassLoader.loadClass() is called on the context classloader and when that fails, Class.forName() is called. On WebLogic, multiple classloader levels (bootstrap, extension, system and application) are searched (probably twice) before it can be determined that a token is not a valid class, and this is really killing performance.
I patched Hibernate code to skip tokens which didn’t start with a Java identifier character or which were reserved HQL keywords. This seemed to do the trick; the time spent on upfront query compilation on my machine went from around 5 ½ min to less than 20 sec."
The patch mentioned above was applied to org.hibernate.hql.classic.QueryTranslatorImpl.getEntityPersisterUsingImports(String) and looks like:
Code:
private static final String [] HQL_KEYWORDS = {"and", "like", "null", "or", "And",
"OR", "in", "AND", "Or", "between", "IS", "upper",
"LOWER", "lower", "LIKE", "IN", "NULL", "is"};
private static final Set EXCLUDED = new HashSet(Arrays.asList(HQL_KEYWORDS));
Queryable getEntityPersisterUsingImports(String className) {
if (! Character.isJavaIdentifierStart(className.charAt(0)) ||
EXCLUDED.contains(className)) {
return null;
}
// ... Rest of existing code
}
The above's obviously not good for production use, but it did the trick in our environment.
I'm a bit curious as to whether something similar to the above can be rolled in, viz. can Hibernate code ensure that it doesn't try to call Class.forName() or ClassLoader.loadClass() for tokens which definitely can't resolve to Java class names?
If you got this far, thanks for your patience!
Regards,
Hemanta