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

Reply via email to