Hibernate, GWT and Gilead: sessions, transactions and caches
I am writing a GWT application, using Hibernate at the server side. Right now, I am entirely confused about the correct way to transfer my objects to the client side of the GWT application in the least amount of code. I am using Gilead to avoid having to double the amount of classes in my domain model [1].
First off, my question is how I should be opening sessions and transactions. Initially, I did this on every RPC server call:
// begin rpc call
getCurrentSession
beginTransaction
// ...do stuff
commit
// session is automatically closed
// end rpc call
Since this opens and closes a Session for every RPC call, does this also create a new connection to the database server every time?
Anyway, as soon as I start using lazily loaded collections, I get the following exception using this pattern:
org.hibernate.HibernateException: collection is not associated with any session
at org.hibernate.collection.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:449)`
It seems to me that the session is closed before Gilead gets a chance to serialize the collection object and this causes the exception.
So I tried to remedy this by explicitly opening the Session myself, which prevents it from being closed automatically after every transaction, like so:
openSession
// begin rpc call
beginTransaction
// ...do stuff
commit
// end rpc call
// next rpc call
beginTransaction
// ...etc
However, when I'm doing this, I'm seeing all kinds of funky behavior related to the Session object cache. For one thing, createQuery().executeUpdate() does not seem to invalidate the session cache, although I've read on various sites that it should. When I tried to remedy that by trying to invalidate the session cache by calling various permutations of session.flush(), session.clear() and so on, the next error was a "ClassCastException: null" on serialization deep inside Gilead or Beanlib.
For another thing, when I'm trying something like this:
clients get an object from the server
client modifies object
client sends object back
server calls session.saveOrUpdate()
I'm getting an error like "a different object with the same identifier is already in the session cache".
What is the proper way to do set this sort of thing up? How should I scope my sessions and how should I treat the cache? I can't imagine I'm the only one trying this and having problems with it, but good gu开发者_运维技巧ides seem to be hard to come by.
[1] http://code.google.com/webtoolkit/articles/using_gwt_with_hibernate.html
Take a look a this answer and the comments below.
The question there is not the same as yours - it is a generalization of yours - i.e. how to combine JPA(Hibernate) with remoting (i.e. serializing objects and sending them to be read over-the-wire). It is not an easy and trivial problem, though it is a common one. Check my suggestions there, and make a comment here if you don't understand something.
I do not use Gilead so that may be part of the problem, but I use ThreadLocal sessions. In each rpc call, I wrap the logic in a method that always closes the ThreadLocal session before the final return. The session is opened for that thread the first time it's requested.
However, you have to fully initialize any proxies before you close the session. Most likely, GWT is trying to serialize your POJO after the session has been closed and when it's gets to a proxy or a lazy collection, it inadvertently tries to initialize it. Personally, I either take the hit of copying the POJOs to separate objects or I make sure I know exactly which fields are going to be serialized and 'touch' them ahead of time (for example, by invoking size() on a collection. But it's difficult if you have a deeply nested objects.
It would be nice if there was a GWT hook that let you execute code after serialization but before the rpc thread completes. It's possible that there is and I just don't know about it.
精彩评论