persistence@glassfish.java.net

Re: Question about the state of entities at rollback

From: Ecmel Ercan <ecmel.ercan_at_gmail.com>
Date: Fri, 20 Apr 2007 21:06:36 +0300

Hi David,

It is not easy to loose the cache :) This article was helpful for me:
http://weblogs.java.net/blog/guruwons/archive/2006/09/understanding_t_1.html

Also this : http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-extensions.html


Regarding lazy loading, according to JPA spec it is optional to
implement it. For practical reasons I don't even use it.



On 4/20/07, David Van Couvering <david_at_vancouvering.com> wrote:
> Thanks, Ecmel, this does sound like it should work.
>
> I am a little concerned about performance, because by closing the
> EntityManager you lose the entire cache. All the caching work of a JPA
> implementation is basically tossed out.
>
> It makes me wonder: at least while you're staying in a single execution
> thread, wouldn't you just do em.close() if there is an exception? You
> could use ThreadLocal to put a different entity manager on each thread...
>
> Also, although it's cool that TopLink handles lazy loading for detached
> objects, this isn't portable, which to me in my environment is a
> problem. If I were to switch to OpenJPA for example it could be that
> all my code would start breaking because fields that used to be valid
> are now null. Maybe this issue is something we could fix in the spec so
> that you can rely on detached objects working with lazy loading across
> implementations...
>
> Thanks,
>
> David
>
> Ecmel Ercan wrote:
> > Hi,
> >
> > I use JPA in Java SE, and after some trial and error I finally
> > decided to use detached objects, considering the following
> > assumptions:
> >
> > 1. EntityManagerFactory (emf) is thread safe.
> > 2. EntityManager (em) is NOT tread safe but it is cheap to create one
> > whenever you need.
> > 3. NO exceptions in JPA is recoverable.
> >
> > So, I use only one emf per application and whenever I need to access
> > persistence context I do the following:
> >
> > EntityManager em = emf.createEntityManager();
> > EntityTransaction tx = null;
> > try {
> > tx = em.getTransaction();
> > tx.begin();
> > ...
> > ...
> > tx.commit();
> > } catch(Exception ex) {
> > if(tx != null && tx.isActive()) tx.rollback();
> > } finally {
> > em.close();
> > }
> >
> > As soon as em.close() is called, your POJOs will become detached so
> > there is no need to copy them explicitly.
> >
> > For lazy loading, TopLink has a special feature where the detached
> > instances still have access in their proxies to retrieve additional
> > dettached instances, so practically you don't have to do anything to
> > reach lazy instances.
> >
> > Hope helps.
> >
> >
> > On 4/19/07, David Van Couvering <david_at_vancouvering.com> wrote:
> >> Hi, all.
> >>
> >> I've been implementing some code against JPA and I was trying to figure
> >> out how to handle a transaction rollback. I wasn't sure if JPA is
> >> responsible for rolling back the state of any objects in the persistence
> >> context.
> >>
> >> The answer appears to be no, and I found this in the spec:
> >>
> >> ===
> >> 3.3.2 Transaction Rollback
> >>
> >> For both transaction-scoped and extended persistence contexts,
> >> transaction rollback causes all pre-existing managed instances and
> >> removed instances[15] to become detached. The instances' state will be
> >> the state of the instances at the point at which the transaction was
> >> rolled back. Transaction rollback typically causes the persistence
> >> context to be in an inconsistent state at the point of rollback. In
> >> particular, the state of version attributes and generated state (e.g.,
> >> generated primary keys) may be inconsistent. Instances that were
> >> formerly managed by the persistence context (including new instances
> >> that were made persistent in that transaction) may therefore not be
> >> reusable in the same manner as other detached objects—for example, they
> >> may fail when passed to the merge operation.
> >> ====
> >>
> >> As an app writer, this statement is somewhat disconcerting.
> >>
> >> I was wondering if you could give me some guidance for how I can write
> >> an app against JPA that handles rollback correctly.
> >>
> >> I'm writing a controller that interacts with entity objects, passing
> >> them around to various methods, storing them in member variables, and so
> >> on. I don't want to detach them, because (a) it is costly for me to copy
> >> all the data into a separate, detached instance, and then during the
> >> merge operation to have them copied back into the instance stored in the
> >> persistence context and (b) I never know if I can access a field or
> >> relationship because I don't know if the field or related instance has
> >> been loaded yet. When I keep them attached, JPA takes care of this for
> >> me.
> >>
> >> Then I perform a persist() operation and it fails and rolls back. This
> >> means all my objects I've been passing around and storing in various
> >> places are suddenly detached and "may be" in an inconsistent state
> >> (which from the perspective of a program is the same as saying they
> >> *are* in an inconsistent state), and thus are invalid.
> >>
> >> So now what do I do? Is there a recommended approach for dealing with
> >> this? How does my application detect this in some global way, and
> >> reloads all the instances it was keeping around from the persistence
> >> context?
> >>
> >> The other concern I have is I'd like consumers of my controller to use
> >> entity objects as POJOs without having to know or care if they are
> >> entities. But the rollback semantics means my callers have to deal with
> >> handling a rollback. Alternately I could pay the copy cost of detaching
> >> my objects before passing them up to higher levels, but then my caller
> >> will still have to deal with the semantics of detached objects (e.g.
> >> lazy fields or associated instances may be null). I don't see any way to
> >> expose entities directly to higher levels of my app that are
> >> entity-unaware... Which means I have to wrap my entities into proxy
> >> classes that handle all the JPA semantics internally and don't expose
> >> this to the caller.
> >>
> >> I am concerned that the rollback consequences can slip past developers,
> >> who will then build apps that behave very erratically after a
> >> transaction rollback. I know it's in the spec, but having worked with
> >> lots of developers, most of them don't read the spec, but instead
> >> cut-and-paste from examples. It would be great if we did a blog about
> >> this, and provided some code showing how to do it right... I could do
> >> this, but before I do I thought I'd check with you all first for any
> >> thoughts you have on this.
> >>
> >> Thanks!
> >>
> >> David
> >>
>