Allen:

Your suggested pattern is workable, but you'll need to make begin() and commit() conditional and smart about transaction demarcation; it is a common pattern to conditionally begin a transaction only if there isn't one on the current thread, and you'll find that in many infrastructures (see my comments on Section 2 in the design proposal).

What happens if you don't have that logic? You'll find that the operations that you choose to make transactional can't be easily composed, which is a very awkward property to have. If you ever need to compose two operations, you would need to write a third method that includes all of the operations of the originals, and not just calling the two original methods, but copying their innards. I actually went through a period of trying to code apps this way in the 90's before infrastructures like EJB started to normalize the conditional demarcation patterns in Java. Lesson learned.

The patterns for transaction demarcation in the dispatch layers involve three parts: (1) demarcation for requests on a per-request basis in a Filter or some other centralized dispatch point (e.g. in Axis or Struts apps in extensions of these servlets wrapping the entry points) (2) for scheduled tasks, wrapping the run() method in a base class (3) providing a mechanism to get an independent transaction for individual units of work at smaller granularities (REQUIRES_NEW style semantics), which I expect would be used very rarely in Roller. Patterns like this work well for two-tier web apps like Roller where the persistence container and the webapp container are the same. They don't work (or require much stronger transaction infrastructure) if you separate the webapp container from the persistence container which does not apply in Roller's case.

Like your proposal, the dispatch-level patterns remove begin() and commit() from app code, and we should end up with only a few places that call them.

--a.


Allen Gilliland wrote:
On Thu, 2006-03-09 at 14:21, David M Johnson wrote:
On Mar 9, 2006, at 5:02 PM, Allen Gilliland wrote:
i feel like we are still a little disconnected here. my approach will not alter anything about our ability to use the open session in view pattern. the only difference i see is the difference between these 2 code blocks ...

old way:
begin();
website.store();
commit();

new way:
WeblogManager wmgr = roller.getWeblogManager();
wmgr.saveWebsite(website);
But what if saving a website is just one step in a multi-part transaction? OK, scratch that. If you start by doing the analysis and designing one of the new Manager interfaces, I think we'll have a much better understanding of this proposed refactoring.

i'll just give the short answer now.  usually things that are multipart 
operations are still part of a single logical operation.  in fact, we already 
do this in some places.  take a look at the UserManager.createWebsite() method. 
 that is a logical method which wraps a series of persistence operations.  so 
the difference would be ...

old way (in struts action or servlet):
begin();
// setup website
website.store();
// setup template
template.store();
// setup category
category.store();
// etc etc
commit();

new way (logical method in manager class):
UserManager umgr = roller.getUserManager();
umgr.createWebsite(newWebsite, possible, other, data);

when i use the new way i only care wether or not the operation succeeded and i 
don't have to think about the persistence implications because they are hidden 
from me.  now if it turns out that we have way too many transactions that would 
need their own logical method in a manager class then maybe this approach won't 
work, but i believe that in most request/response cycles the operations are 
pretty isolated and simple.  in most of them you are only 
creating/updating/deleting a single object at a time.

-- Allen


- Dave





Reply via email to