Adam, In some I can agree and have done exactly what you are talking about with aspectj. Every approach has its pluses and minuses so I would say go with what makes sense for your application.
Ron On 8/11/09 8:28 PM, "Adam B" <[email protected]> wrote: > That's pretty cool, Andy. Thanks. Having virtually zero experience with > AspectJ I'm pleasantly surprised by it's apparent power. From my perspective, > as a noob, this actually looks more understandable than any of the Spring > examples I've seen thus far. Then again, I find myself gravitating towards > DIY solutions as opposed to big frameworks. > > Andy Clement wrote: >> and i'll just chip in. I do think AspectJ can help with your logic - but >> Spring may be a good answer too. >> >>> > Can AspectJ be used somehow to automatically install a hook inside the >>> catch(C_DoesNotExist) block? If so that would let me make the rollback >>> implicit. >> >> something like that is simply: >> >> before(): handler(C_DoesNotExist) {...} >> >> to choose a particular catch block you also throw in a cflow(...) or a >> withincode(...) >> >> but just exploring some options, here are some possibilities: >> >> // remove all the 'stuff' from doOperationX >> around(): execution(@Transactional * *(..)) { >> >> connection = get_connection() >> connection.start_transaction() >> try { >> proceed(); >> >> connection.commit(); >> } finally { >> connection.end_transaction() //rolls back uncommitted >> connection.close() >> } >> } >> >> // if calling updateC from updateB and it fails, just ignore it >> >> around(): call(* updateC(..)) && withincode(* updateB(..)) { >> try { >> proceed(); >> } catch (C_DoesNotExist) { >> // ignore >> } >> } >> >> >> >> @Transactional function doOperationX() >> { >> >> updateA(connection) >> updateB(connection) >> } >> >> function updateA(connection) { >> connection.execute("UPDATE a SET ...") >> } >> >> function updateB(connection) { >> connection.execute("UPDATE b SET ...") >> >> updateC(connection) >> } >> >> function updateC(connection) { >> result = connection.execute("SELECT c.id <http://c.id/> FROM c INNER >> JOIN b ON ...") >> if (result.next()) >> >> connection.execute("UPDATE c SET ...") >> else >> throw C_DoesNotExist() >> } >> >> Andy >> >> >> >> 2009/8/11 Adam Bennett <[email protected]> >> >>> >>> ORM would probably be too much change at once - much of our code base is >>> very procedural. We might consider Spring because it sounds like it could >>> be refactored in incrementally. Yet I fear that even with Spring it is >>> still the programmers responsibility write explicit rollback logic when >>> catching exceptions (I need to read up on Spring though). >>> >>> Can AspectJ be used somehow to automatically install a hook inside the >>> catch(C_DoesNotExist) block? If so that would let me make the rollback >>> implicit. >>> >>> >>> >>>> >>>> >>>> From: Ron Difrango [mailto:[email protected]] >>>> >>>> To: [email protected] >>>> >>>> Sent: Tue, 11 Aug 2009 07:01:08 -0700 >>>> >>>> Subject: Re: [aspectj-users] Database transactions and exceptions don t >>>> mix! (can AspectJ help?) >>>> >>>> >>>> >>>> My initial reaction to this, is why don¹t you use either an ORM framework >>>> or Spring to help you manage the transactions? >>>> >>>> >>>> On 8/10/09 11:39 PM, "Tahir Akhtar" <[email protected] >>>> <http://[email protected]> > wrote: >>>> >>>> >>>> >>>> >>>> >>>>> You might want to read : InfoQ: Java Transaction Design Strategies >>>>> <http://www.infoq.com/minibooks/JTDS> >>>>> http://www.infoq.com/minibooks/JTDS >>>>> >>>>> Adam Bennett wrote: >>>>> >>>>>> >>>>>> Lately I've been trying to improve how our web application employs >>>>>> transactions (we don't use them enough). While doing this I became aware >>>>>> of this rather general problem. It seems as though database transactions >>>>>> cannot be mixed with exceptions unless great vigilance is practiced. I'm >>>>>> wondering if AspectJ can help me in some way. >>>>>> >>>>>> Consider this pseudo code: >>>>>> >>>>>> >>>>>> function doOperationX() >>>>>> { >>>>>> connection = get_connection() >>>>>> connection.start_transaction() >>>>>> try >>>>>> { >>>>>> updateA(connection) >>>>>> >>>>>> try >>>>>> { >>>>>> updateB(connection) >>>>>> } >>>>>> catch (C_DoesNotExist) >>>>>> { >>>>>> //ignore (non fatal) >>>>>> } >>>>>> >>>>>> connection.commit() >>>>>> } >>>>>> finally >>>>>> { >>>>>> connection.end_transaction() //rolls back uncommitted >>>>>> connection.close() >>>>>> } >>>>>> } >>>>>> >>>>>> function updateA(connection) >>>>>> { >>>>>> connection.execute("UPDATE a SET ...") >>>>>> } >>>>>> >>>>>> function updateB(connection) >>>>>> { >>>>>> connection.execute("UPDATE b SET ...") >>>>>> updateC(connection) >>>>>> } >>>>>> >>>>>> function updateC(connection) >>>>>> { >>>>>> result = connection.execute("SELECT c.id <http://c.id> FROM c INNER >>>>>> JOIN b ON ...") >>>>>> if (result.next()) >>>>>> connection.execute("UPDATE c SET ...") >>>>>> else >>>>>> throw C_DoesNotExist() >>>>>> } >>>>>> >>>>>> >>>>>> >>>>>> Don't study the pseudo SQL too closely, the problem isn't there. Read the >>>>>> code like this: >>>>>> >>>>>> 1) operationX requires updating of A and, optionally, B. >>>>>> 2) Internally, updating B always requires that C also be updated. All or >>>>>> nothing. >>>>>> 3) Sometimes, C cannot be updated because the database is not in the >>>>>> proper state at this time. (Not an invalid state, mind you) >>>>>> 4) operationX knows that C might not be updatable, so it catches the >>>>>> exception and ignores it. >>>>>> >>>>>> The problem is: >>>>>> >>>>>> updateB() leaves the database in an inconsistent state if an exception >>>>>> is thrown >>>>>> out of updateC(). The inconsistency is that table B has been updated >>>>>> but D has >>>>>> not been updated accordingly. >>>>>> >>>>>> Yet, it's only a problem because operationX caught the exception. Had it >>>>>> let the exception continue up, the finally block would have rolled back >>>>>> the entire transaction quite nicely. >>>>>> >>>>>> How can I avoid this problem? The only proper solution that I can see is >>>>>> a prolific use of transaction checkpoints (aka savepoints) so that a >>>>>> partial rollback can occur if needed: >>>>>> >>>>>> >>>>>> function updateB(connection) >>>>>> { >>>>>> success = false >>>>>> savepoint = connection.setSavepoint() >>>>>> try >>>>>> { >>>>>> connection.execute("UPDATE b SET ...") >>>>>> updateD(connection) >>>>>> success = true >>>>>> } >>>>>> finally >>>>>> { >>>>>> if (not success) >>>>>> connection.rollback(savepoint) >>>>>> } >>>>>> } >>>>>> >>>>>> >>>>>> >>>>>> But this hurts performance considerably and requires programmer vigilance >>>>>> and lots of extra code! The programmer must remember that: >>>>>> >>>>>> **If your function does more than one update it MUST use a savepoint!** >>>>>> >>>>>> That's tough pill to swallow (for me). I try to avoid programming models >>>>>> that require programmer vigilance. All it takes is one groggy Monday... >>>>>> >>>>>> What do you think? Am I missing a better solution? Can AspectJ help? >>>>>> >>>>>> Videx Inc. 1105 N. E. Circle Blvd. Corvallis OR 97330 (541) 758-0521 >>>>>> CONFIDENTIAL COMMUNICATION: The email message and any attachments are >>>>>> intended only for the addressee. They may be privileged, confidential, >>>>>> and protected from disclosure. If you are not the intended recipient, any >>>>>> dissemination, distribution, or copying is expressly prohibited. If you >>>>>> received this email message in error, please notify the sender >>>>>> immediately by replying to this e-mail message or by telephone >>>>>> >>>>>> _______________________________________________ >>>>>> aspectj-users mailing list >>>>>> [email protected] <http://[email protected]> >>>>>> https://dev.eclipse.org/mailman/listinfo/aspectj-users >>>>>> >>>>>> >>>>>> >>>>>> >>>>> >>>>> >>>>> >>>>> >>>>> _______________________________________________ >>>>> aspectj-users mailing list >>>>> [email protected] <http://[email protected]> >>>>> https://dev.eclipse.org/mailman/listinfo/aspectj-users >>>>> >>>> >>>> >>>> >>>> >>>> Ron DiFrango >>>> Manager and Architect | CapTech Ventures >>>> (804) 855-9196-6308 | [email protected] >>>> <http://[email protected]> >>>> >>>> >>> >>> >>> >>> >>> >>> Videx Inc. 1105 N. E. Circle Blvd. Corvallis OR 97330 (541) 758-0521 >>> CONFIDENTIAL COMMUNICATION: The email message and any attachments are intend >>> ed only for the addressee. They may be privileged, confidential, and protec >>> ted from disclosure. If you are not the intended recipient, any disseminatio >>> n, distribution, or copying is expressly prohibited. If you received this e >>> mail message in error, please notify the sender immediately by replying to t >>> his e-mail message or by telephone >>> >>> >>> >>> _______________________________________________ >>> aspectj-users mailing list >>> [email protected] >>> https://dev.eclipse.org/mailman/listinfo/aspectj-users >>> >>> >> >> >> >> >> >> >> _______________________________________________ >> aspectj-users mailing list >> [email protected] >> https://dev.eclipse.org/mailman/listinfo/aspectj-users >> > > > > > Videx Inc. 1105 N. E. Circle Blvd. Corvallis OR 97330 (541) 758-0521 > CONFIDENTIAL COMMUNICATION: The email message and any attachments are intended > only for the addressee. They may be privileged, confidential, and protected > from disclosure. If you are not the intended recipient, any dissemination, > distribution, or copying is expressly prohibited. If you received this email > message in error, please notify the sender immediately by replying to this > e-mail message or by telephone > > > _______________________________________________ > aspectj-users mailing list > [email protected] > https://dev.eclipse.org/mailman/listinfo/aspectj-users
_______________________________________________ aspectj-users mailing list [email protected] https://dev.eclipse.org/mailman/listinfo/aspectj-users
