I'd like to discuss how to best use (JPA) transactions with RequestFactory.
As a basis, I'm assuming the approach where one user interaction should
normally result in one DB transaction, so that the whole interaction can
either fail or succeed, atomically.
The first thing to consider with RequestFactory is, that each method call
in a RequestContext can succeed or fail individually. Also note, that the
fire() call will (usually) succeed as a whole, even if one of the
RequestContext method calls fails.
So for example, if you have
ctx.opA().to(receiverA);
ctx.opB().to(receiverB);
ctx.fire(receiverX);
Then this may result in the sequence
receiverA.onSuccess(),
receiverB.onFailure(),
receiverX.onSuccess().
What this means is, that you get atomicity only for the individual
RequestContext methods. Therefore you definitely shouldn't wrap the entire
RequestFactoryServlet's onPost() method in one transaction, but rather only
the individual service method implementations individually. (Otherwise, the
client may believe, that opA has succeeded, while in reality the entire
transaction was rolled back.)
And if you need a transaction with multiple objects involved, you will have
to wrap the entire interaction in one service method call.
*Side note: Convenience solution*
*
*
If you grow tired of wrapping each service method implementation in a
transaction individually, you may want to use your own
ServiceLayerDecorator in the RequestFactoryServlet constructor, and
override invoke() like this:
@Override
public Object invoke(final Method domainMethod, final Object... args) {
// Note: Ideally use dependency injecton for this:
final EntityManager em = getRequestScopedEntityManager();
try {
em.getTransaction().begin();
final Object result = super.invoke(domainMethod, args);
em.getTransaction().commit();
return result;
} catch (final Error e) {
em.getTransaction().rollback();
throw e;
} catch (final RuntimeException e) {
em.getTransaction().rollback();
throw e;
}
}
(Better solutions are welcome!)
*Question/Discussion:*
There is however a little issue that remains: RequestFactory calls
Locator.find() outside of such a transaction:
1. In RequestState.getBeansForPayload(), which calls
ServiceLayerDecorator.loadDomainObjects()
2. In SimpleRequestProcessor.createReturnOperations, which calls
ServiceLayerDecorator.isLive()
I think, it's possible to pretty much ignore this (at least if you don't
use isolation levels higher than READ_COMMITTED, and if your DB is ok with
autocommit style queries), or is it? Note: My Locator's find method re-uses
the same RequestScoped EntityManager instance - so I get the same
underlying Hibernate session with the same first-level cache - it's just
not in the same transaction, that's all.
How do you deal with this? What is the intended transaction concept by the
RequestFactory designers?
--
You received this message because you are subscribed to the Google Groups
"Google Web Toolkit" group.
To view this discussion on the web visit
https://groups.google.com/d/msg/google-web-toolkit/-/ASBa77ljy3cJ.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-web-toolkit?hl=en.