On 10/12/11 24:12 , Niclas Hedhman wrote:
Why doesn't Neo4j handle "the work" in success instead of "finish" ?
I don't know really. I will have to ask Johan about that I think. One thing to note is that finish() will only throw an exception if there are system level exceptions (fail to write to disk etc.), since they do pessimistic locking. In our case complete() can throw optimistic locking exceptions, which needs to be handled normally in a multithreaded environment.
/Rickard
On Tue, Oct 11, 2011 at 12:15 PM, Rickard Öberg<[email protected]> wrote:Hi, Now that I work for Neo Technology I've started looking more in detail into the Neo4j API, and found something very interesting with regard to how transaction completion is handled. The idea is to simplify exception handling. Example code: Transaction tx = ...; try { ... tx.success(); } finally { tx.finish(); } --- At first the above looked a little bit funny to me, but I got it explained that it relates to how you handle exceptions. In the above, if there is any exception (Exception, RuntimeException, Error) then the finish() call will do a rollback, since success() has not been called. This way you don't have to do tx.rollback() in catch statements, since theoretically you would have to catch Throwable to be sure you have covered all cases. I.e. this is unsafe: UnitOfWork uow = ...; try { uow.complete(); } catch (Exception ex) { uow.discard(); } --- ... since it does not handle RuntimeException or Error. So how does this affect us? Not much it turns out, because I realized that uow.discard() on a closed UoW is a no-op. In other words, the following becomes best practice: UnitOfWork uow = ...; try { ... uow.complete(); } finally { uow.discard(); } --- With this template you are sure that the UoW is always handled properly after the block exits. So, is this the same as Neo4j? Turns out, no actually not. The difference is that in Neo4j the work happens in finish(), and so if that method throws a TransactionFailureException, then you need a new try/catch outside of it to handle. In Qi4j, the complete() method does the work (and discard() never throws an exception), and so any exceptions from complete() can be handled in the catch blocks of that try block. This also works if you have multiple UnitOfWork's in one try-block: UnitOfWork uow = uowf.newUnitOfWork(); try { ... uow.complete(); uow = uowf.newUnitOfWork(); ... uow.complete(); } finally { uow.discard(); } Does this seem like a good strategy? Do you prefer the Qi4j variant or the Neo4j variant? Any other pros and cons I've missed? /Rickard _______________________________________________ qi4j-dev mailing list [email protected] http://lists.ops4j.org/mailman/listinfo/qi4j-dev
_______________________________________________ qi4j-dev mailing list [email protected] http://lists.ops4j.org/mailman/listinfo/qi4j-dev

