David-
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 from the persistence context all the instances it was
keeping around?
In my opinion, JPA is pretty weak when it comes to rollbacks. This
might be due to its legacy of being part of the EJB spec, where
individual entity instances typically aren't accessible after a
transaction has completed.
In generic JPA, the only way to deal with the situation you describe
would be to manually call EntityManager.refresh() on each instance
that was involved in the transaction so as to ensure that it is up to
date.
Fortunately, in OpenJPA you have a little more control over the post-
rollback behavior. You can use the openjpa.RestoreState property to
define what should be done with that state of persistent instances
after a rollback occurs. See:
http://incubator.apache.org/openjpa/docs/latest/manual/
manual.html#ref_guide_pc_scos_restore
On Apr 19, 2007, at 4:40 PM, David Van Couvering wrote:
Hi, all. I am hoping you can help me out here. You don't have a
users list so I'm sending it to dev.
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 there is any guidance available 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 let's say 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 from the persistence context all the instances it was
keeping around?
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