FAQs from the Forum
I have CGLIB / reflection optimizer errors or similar when migrating from 2.1 betaX to 2.1 rc1.
Symptoms may be : - java.lang.NoClassDefFoundError during Configuration.buildSessionFactory
- java.lang.IllegalAccessError in net.sf.cglib.core.ClassEmitter.setTarget
- java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.visitMethod(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;)Lorg/objectweb/asm/CodeVisitor;
hibernate 2.1 rc1 and above now use CGLIB 2. Remove your old CGLIB jar from your classpath and replace it with the one shipped with hibernate2 (./lib/cglib2.jar). Note: From the forum (Chris Nokleberg)
Caused by: java.lang.NoSuchMethodException: java.sql.Statement.execute(java.lang.String, [B)
at java.lang.Class.getDeclaredMethod(Class.java:1256)
at java.sql.PreparedStatement$$EnhancerByCGLIB$$3c240523.<clinit>(<generated>)
I've confirmed this is a bug in CGLIB2, a fix will be in the next version distributed with Hibernate. Alternatively, you can try building CGLIB from CVS and replacing the cglib2.jar file that ships with Hibernate 2.1 RC1. http://forum.hibernate.org/viewtopic.php?t=925978&start=0&postdays=0&postorder=asc&highlight=
Storing Big5 or Unicode Strings
Data has some String fields that stores Chinese Big5 encoding String , ex: Title and Description; I use DAO pattern , and in the implementation code , when persisting 'Data', I have to manually change the String encoding from Big5 to 8859_1 to be able to store it to MySQL. I found the final solution: In hibernate.cfg.xml:
<property name="connection.url">jdbc:mysql://host/db?useUnicode=true&characterEncoding=Big5</property>
Both uneUnicode = true , and characterEncoding=Big5 are needed and make sure to 'escape' the '&' character.
I've got problems with legacy tables with UPPERCASE/lowercase identifiers
You can easily quote the table names in the mapping file, using backticks:
<class table="`TableName`" ..... >
I've got problems with WebLogic and JNDI, how does it work?
This forum believe there's some problem if you do it the regular way like most app server. Therefore, try the following (which works for me). Use a WLS Startup class to bind Hibernate Session Factory object in WLS JNDI. Here's an excerpt of a possible code:
public class WLSStartup implements T3StartupDef
{
public static final String SESSION_FACTORY_JNDI = "hibernate";
public static final String URL = "t3://localhost:7001";
/**
* Called by WebLogic server upon startup. This is where everything should
* be initialzed.
*
* @param name the JNDI name of this class
* @param args any input parameters
*
* @return the status.
*
* @throws Exception in case of any error
*/
public String startup( String name, Hashtable args ) throws Exception
{
String METHOD_NAME = "startup ";
// Bind the various Hibernate Object to the Weblogic JNDI
try
{
log ( METHOD_NAME + " Going to bind Hibernate object. " );
doBind( );
log ( METHOD_NAME + " Bound Hibernate object!" );
}
catch ( Exception exception )
{
log ( METHOD_NAME + " Exception while binding Hibernate Object to Weblogic JNDI" );
exception.printStackTrace ( );
}
return "WLS Startup completed successfully";
}
/**
* Performs Hibernate objects to Weblogic JNDI Namespace bindings.
* It gets the initial context and binds the Hibernate objects to it.
*
* @param None
* @throws Exception in case of any errors
*/
private static void doBind( ) throws Exception
{
Properties environment = null;
InitialContext context = null;
try
{
//Properties for storing JNDI configuration information
environment = new Properties( );
//Add initial context factory
environment.put( Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
environment.put( Context.PROVIDER_URL, URL );
log( "Constructing an Initial Directory Context object" );
context = new InitialContext( environment );
Datastore ds = Hibernate.createDatastore();
SessionFactory factory = ds.buildSessionFactory();
if (factory == null)
throw new Exception("SessionFactory cannot be built?!");
try
{
if( context.lookup(SESSION_FACTORY_JNDI ) != null )
context.rebind(SESSION_FACTORY_JNDI, factory );
else
context.bind(SESSION_FACTORY_JNDI, factory );
}
catch ( NamingException nameEx )
{
context.bind(SESSION_FACTORY_JNDI, factory );
}
}
catch ( NamingException nameExp )
{
throw new Exception( "NamingException: " + nameExp.getMessage( ));
}
catch( Exception excp )
{
throw excp;
}
finally
{
if( context != null )
{
try
{
context.close( );
context = null;
}
catch ( NamingException nameExp )
{
throw new Exception( "NamingException for context close: " nameExp.getMessage( ));
}
}
environment = null;
}
}
Jar up the relevant Hibernate jar files and configure this Startup class under WLS console. Then at your JNDI client (Servlet or EJBs for example) you can have a code similar to this excerpt below: -
Object objref;
Context context;
Hibernate.configure();
//The usual WLS JNDI context
context = getInitialContext();
objref = context.lookup(WLSStartup.SESSION_FACTORY_JNDI);
sessionFac = (SessionFactory) PortableRemoteObject.narrow(objref, SessionFactory.class);
if sessionFac == null)
throw new Exception("Null SessionFactory found?!");
Works great with Struts 1.1 on WLS 6.X and 7.X. I've tested by writing some subclass relationship data into Oracle 8i! Any questions can be directed to simon@see-consulting.com.
MS SQL Server with JSQLConnect driver throws exception with delete()
Hibernate 2.0.1 propagates an exception from Session.flush() following Session.delete(Object):
net.sf.hibernate.HibernateException: SQL update or deletion failed (row not found)
at net.sf.hibernate.impl.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:25)
NonBatchingBatcher.addToBatch expects PreparedStatement.executeUpdate() to return 1, but it returns 0 in this case, even though it has deleted 1 row from the database. I solved this problem by appending "/lastUpdateCount=true" to the JDBC url for JSQLConnect. This makes the JDBC driver behave as Hibernate expects. Without this property, it seems the driver returned the number of rows updated by a trigger that was executed as a side-effect of the requested change. See http://www.j-netdirect.com/JSQLConnect/TechnicalReference.html#ConnectSettings for more information.
Should I GROUP BY all object attributes in HQL?
At present you need to explicitly enumerate all the employee properties in the GROUP BY. This might be a wrinkle in HQL, or it might actually be OK.
SELECT e
FROM Employee e
LEFT JOIN Customer c AS c.staff.id
WHERE e.team.id = :id
GROUP BY e.firstName, e.lastName, e.salary
ORDER BY count(c.staff.id) ASC
"Flush during cascade is dangerous" with own equals() method
When you delete child object from collection like described in documentation and - Use proxy for you persistent class
- Overwrite equals method for your class
- Use class comparison checking in your equals() like this
if( !(o.getClass() == getClass()) ) return false;
You may get an error because both classes are not identical. Use instanceof instead.
How to handle transactions that span multiple data access objects?
Consider a business controller that needs to delegate to 2 DAOs for a certain use case. The processing is supposed to occur within a single transaction. How to inform your DAOs that they need to participate in the surrounding transaction, instead of opening their own Hibernate Session? And how to make them run in their individual transactions else? Passing around a Session instance as parameter to the DAO methods is not desirable, as such a required parameter is inconvenient, and the DAO interfaces should not be Hibernate-specific. A RYO solution according to the ThreadLocal Session pattern will work but tie the business controllers to Hibernate for transaction demarcation. The goal is to make DAO interfaces agnostic of both the data access mechanism of an implementation and the actual transaction strategy of the caller. This allows for e.g. mixing Hibernate DAOs and plain JDBC DAOs with either native Hibernate transactions or JTA. A generic transaction mechanism is needed, with support for passing thread-bound Hibernate Sessions or JDBC Connections or whatever. The Spring Framework provides such generic transaction management in a very lightweight way, with first-class support for Hibernate, backed by either native transactions or JTA. There is also respective support for JDO and plain JDBC. Transactions can be demarcated either programmatically or declaratively via an AOP interceptor. The generic management helps to avoid tying business objects to a particular transaction strategy. Furthermore, Spring's lightweight bean container offers means for wiring up an application, e.g. a middle tier that consists of business objects, data access objects, and resources. Spring also provides generic AOP support within the bean container, and sophisticated convenience support for plain JDBC access. Note that Spring's individual parts can be reused on their own easily, as they are as loosely coupled as possible. Data Access with the Spring Framework
What is the precedence for the methods in the Lifecycle and Interceptor interfaces?
Save or Update: Save: - Lifecycle.onSave
- Interceptor.onSave
Update: Load: - Interceptor.onLoad
- Lifecycle.onLoad
Delete: - Interceptor.onDelete
- Lifecycle.onDelete
Flush: - Interceptor.preFlush
- Interceptor.findDirty
- Interceptor.onFluchDirty
- Interceptor.postFlush
Hibernate startup is slow, what can I do?
I just discovered the new cglib version available at cglib.sf.net. Using the new library has cut my Hibernate startup configuration times from sometimes 3 minutes (I had over 70 persistent classes) to nearly nothing. This has been a godsend, given the nature of the app is that it has to be restarted for every code change -- debugging could be a nightmare. If not allready done could you (Gavin) start packaging this newer version with Hibernate -- it's a real time saver. Luke Monahan You need to remove bcel.jar from classpath and use asm.jar for performance ( BCEL has priority in cglib 1.0 ). We will drop BCEL in the next version. Juozas Baliuka
MS SQL performance and unicode (indexing of VARCHARs)
Am I the only person in the world who didn't know what happens if you use VARCHAR's with Java and the MS SQL JDBC driver? It seems unlikely because I can find no mention of this in the list archives or the like. If you use VARCHARs for database tables and index those columns either (as a primary key or not) , then you will find that without this option sendStringParametersAsUnicode=false set on the JDBC driver string, all queries will use a table scan rather than the index to access rows. This is somewhat annoying with large tables (as you can imagine). The reason is that the JDBC driver marks the string as an NVARCHAR so when the execution plan is created, it includes the conversion of the row's VARCHAR to an NVARCHAR. This stops SQL Server from using an index and you end up with a very slow query. What gets even more annoying (and potentially confusing) is that this does not happen with direct queries, only prepared statements (hence the issue with hibernate). It might be wise to make note of this fact in the FAQ or documentation. I only found 1 article on google in a news group that mentions this (and I am indebted to that person for enlightening me...) The article: on Google Groups From: Gary Evesson <gevesson@decentrix.com>
I'm getting a java.lang.ExceptionInInitializerError with JDK 1.3
Hibernate is build with the latest stable JDK 1.4, this error may be a binary incompatibility with JDK 1.3. Recompile the hibernate.jar (ant jar) with JDK 1.3. It looks like this is a combination/issue with both Tomcat and the JDK. Here's the old thread: http://sourceforge.net/forum/message.php?msg_id=2062040 If anyone is able to reproduce and debug this issue, please add to this FAQ entry.
Follow up: Hi, we are a develop team at Universidad de las Americas, Puebla in Mexico and we got the same problem trying to run a web app using hiberante, the app was developed using JSDK 1.4, but in the real enviroment it was suposed to run on a JSDK 1.3, all we did to get it running was: 1) upgraded to the last stable version of the 1.3 platform 2) recompiled the hiberante source with this version (all though any 1.3 version seems to do fine) 3) get the apropiate jdbc drivers for the jsdk and database and that's it, the app is running on a JSDK 1.3 enviroment using all the virtuous functions in hibernate :)
I'm getting "Too many tables. MySQL can only use 31 tables in a join"
You can set outer-join="false" on associations or, in Hibernate 2.1, use hibernate.max_fetch_depth.
Websphere 5 produces a com.ibm.websphere.ce.cm.StaleConnectionException: Connection is closed
Unfortunately on WebSphere 5.0 I get the following error message when closing a Hibernate Session: net.sf.hibernate.util.JDBCExceptionReporter TRAS0014I: The following exception was logged com.ibm.websphere.ce.cm.StaleConnectionException: Connection is closed We had this same problem with data source connections in Websphere. We "fixed" it by configuring the data source to "Disable auto connection cleanup". It's a checkbox in the data source setup in Websphere.
What are the rules for the SQL String passed in the new createSQLQuery"
There is an excellent thread about this, see http://forum.hibernate.org/viewtopic.php?t=418 Rules: #01: All of the columns must be specified, either via {alais1}.* or by explicitly listing each. [to be continued]
Hibernate crashes on this Sun RAQ server. What gives?
The problem with most Sun RAQs is that they are loaded with pretty old (and I guess stable) versions of Java (version 1.3 is old now, OK?!). The problem here is related to a FAQ above in that you get some really odd null pointer exceptions, e.g. when creating the session factory or when hydrating a rowset back into an object. The solution is simple: rebuild hibernate with a similar version of Java to the one on the server. In most cases this is just a case of installing the old version of Java and then setting JAVA_HOME to point to the old Java before running the hibernate build script (shipped with the distribution). From: Russ Freeman <russ@freesoft.co.uk>
Invalid parameter exceptions listed when an object mapping is read
Although the documentation suggests that object properties can be public, private or protected, there is still a restriction on accessing non-public properties via reflection when using a JDK < 1.4. Overcome the problem by making these properties public and document the reason in the code for future mortals! From: Russ Freeman <russ@freesoft.co.uk>
Can I disable the Session cache?
You can't disable it, because that would expose you to stack overflows where there are circular references, etc. You can, however, either clear() it, or change the FlushMode.
Issues with MS SQL Server UID (GUIDs)
MS SQL Server UID is a data type of 16-bytes binary values that operate as globally unique identifiers (GUIDs). In character string format the UID looks like this: '{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}' I found that this data type could cause some problems when used in i.e. loading an object from the database. The following two examples will both have the same result:
session.load(MyObject.class, "{2C90AA1E-00F8-00F8-0001-FFFFF8F40C12}");
, and:
session.load(MyObject.class, "2C90AA1E-00F8-00F8-0001-FFFFF8F40C12");
MS SQL Server seems to remove the brackets from the UID when querying the database. When using this together with Apache JCS the difference between using brackets and not using brackets is crucial! Suppose that MyObject have a one-to-many relationship to MyOtherObject, and this relationship is bi-directional (MyOtherObject have a reference to its parent MyObject). When loading MyObject from database with an UID including brackets, Apache JCS will store this UID (with brackets) as the key used for locating the object in cache. This will cause the related object, MyOtherObject, not finding its parent (MyObject) in the cache and therefore load another instance of the parent MyObject into the cache. The reason for this is; MyOtherObject will have a reference to the parent defined as an foreign key in the database. When MyOtherObject will get loaded it will try to lookup its parent by an UID without brackets! Since we specified to load MyObject by an UID with brackets you wont get a hit in the cache cause MS SQL Server returns the UID from database without brackets. A new instance of MyObject will be created and its key in Apache JCS will be a UID without the brackets. Now we have two instances of the parent MyObject in Apache JCS, one located by its UID with brackets and another located by its UID without brackets. If you load MyObject by its UID with brackets, change the state of the object and then tries to persist the changes to database - it just wont happen! One UPDATE will be performed cause you have changed the state of the instance MyObject stored in Apache JCS located by its UID with brackets, another UPDATE on the related instance MyOtherObject will be performed, and another UPDATE on MyObject will be performed - on the other instance to MyObject handled by MyOtherObject. This instance have not been changed but is different from the instance of MyObject located by its UID with brackets and therefor be persisted into the database with its old values. And since MS SQL Server sees the UID with or without the brackets as same, the updated row in database with the new values will be overwriten with the old values! REMEBER! An UID with brackets or without brackets is handled the same by MS SQL Server, but NOT by Apache JCS. From Andreas Eriksson <andreas_developer@hotmail.com>
|