views:

502

answers:

4

I'm trying to find out the best way to handle transactions at object level (not database level). Short example: 4 objects A, B, C and D. A starts a transaction and calls methods in B and C. Whithin this transaction C is also calling D. The methods being called aren't supposed to always participate in this transaction, but can be called also on their own. Are there any patterns for managing transactions at object level?

I didn't really find something, so I came up with this: Use a TransactionContext where one can register TransactionListeners. If a transaction is started using the TransactionContext, then it will inject the running transaction into each of the registered listeners, which in turn will use a running transaction or elsewise will start one on their own if needed. This way I'm pretty free to decide wether I want an object participating in my transaction or not.

The problem comes when having object calling chains like above. When starting the transaction I just know that B and C must participate in the transaction so I add them to the TransactionContext. But what about D? I don't really want to pass the TransactionContext around to B and C.

I would appreciate some input on my approach as well as some pointers to proven patterns (even better).

+1  A: 

The Spring framework (initially for Java but there's a .Net version too now) can do this. Methods are marked as:

  • Requires a transaction (starts one if there isn't one already);
  • Requires a new transaction (creates a new one always);
  • etc.

This is typically done with annotations. Sounds exactly like what you're describing.

Check out Spring's transaction management.

cletus
I know that Spring and also application server are providing this, but I don't want to use either of them. But thanks for the pointer to Spring transactionmanagemenr. I will read that one.
MicSim
In Java its a pretty standard pattern and many libraries implement it.
Loki
Why wouldn't you want to use JTA or Spring?
Loki
In Java, pretty much the only valid not to use Spring is that your code is running on a mobile phone or in a toaster or something.
cletus
I'm using JPA and Hibernate at the moment, but don't have any experience with Spring yet. I'm trying to keep the app as clean and simple as possible and don't want to add a framework just because I could use just 5% of it.
MicSim
You want to keep things simple by implementing a *transaction* framework?? No, seriously, use this as an opportunity to go learn Spring. Otherwise future coders will be looking at your code, scratching their head, asking themselves "Why didn't he just use Spring?"
cletus
Valid point! I've got to think about it.
MicSim
+1  A: 

"I don't really want to pass the TransactionContext around to B and C."

Why not? They participate and they delegate to yet other objects.

Either

  • Everyone needs to register. Which means you have to delegate registration. A knows that it hands off to B and C. Each of which may (or may not) have further delegatees to register. This is relatively simple to implement with a "RegisterYourselfAndYourDelegatees" method.

  • Eschew the Listener design pattern. Create a transaction context and pass it around. This replaces the registration and injection with a slightly simpler design. However, you'll need to have two Context subclasses -- the real Context and a stub Context that does nothing and is used outside a transaction context.

    This makes your function definitions slightly more complex. For Java, you can use an overloaded naming to have two method functions with different signatures.

    For Python, this is a non-issue; the context is an optional argument.

S.Lott
A: 

I'd suggest: Prevayler

Prevayler is an object persistence library for Java. It is an implementation of the
System Prevalence architectural style, in which data is kept hot in Memory with
changes journaled for system recovery.

Prevayler ' s architecture is illustrated in the diagram shown there. Prevayler [1]
serves as a transactional barrier for the business objects [2] of your application,
held in Memory. You encapsulate all modifications of your business objects into
instances of the Transaction interface [3], much like a " command " pattern
(though different from a command in some details of the pattern). Whenever 
you ask Prevayler to execute a transaction on your business objects [4], Prevayler
first writes the transaction object to a journal [5] so that data is not lost if your
system crashes. Prevayler can also write a snapshot of your entire business object
graph [6] as often as you wish. Prevayler uses the latest snapshot together with
the journals to automatically recover your business objects from disk [7] on
application startup by restoring the snapshot and then re-executing every
transaction that was originally executed after that snapshot was taken.

Of course, you can disable the persistent store and use only the In-memory store.

Banengusk
A: 

Highly recommend this paper by Andrei Alexandrescu and Petru Marginean, which presents ScopeGuard patten. This is an elegant and a very robust solution for managing transactions specifically in presence of exceptions.

Applicable to the problem that you are trying to solve ScopeGuard will allow you to define the scope of your transaction, and easily (meaning automatically) manage that for you whether transaction involves methods A,B,C,D or calling individual methods.