PDA

View Full Version : Adding support for db4o transactions


samokk
02-07-2006, 06:35 PM
Hi,

I need to use db4o (Native OO Database for C#/Java) for one of my projects. However, I don't really see any support for it in Spring...
I got the Spring.Data classes from the sandbox and started playing with them in order to see what's available, and what's left to do..

To be honest, I am a bit lost with all these classes, so I would have a few questions regarding how I should implement things..

1) What is the "right" way of implementing transactions with Spring ? Should all my DAO classes maintain a reference to a Db4oTemplate (yet to code) and use it to execute all queries ?

2) Point 1) would only "enable" the use of transactions, as far as I understand. It is then necessary to demarcate transactions either programatically or declaratively. Declaratively, this is done using the TransactionProxyFactory, right ? Programmatically, with the TransactionTemplate that delegates to the Db4oPlatformTransactionManager, right ?

3) Looking at AdoTemplate, It looks like the role of the template is more or less to :
- TransactionSynchronizationManager.GetResource() to get a ConnectionHolder (The PlatformTransactionManager does the ResourceBind() prior to this call, ok ?)
- Executes the query (either using a ICallback or a delegate)
- Dispose() the resources using a ConnectionUtils

4) What is the logic behind getting transactions from PlatformTransactionManagers ? How it is decided whether a new class is created, or reused, or what ?

5)The objects that we get from the tx managers are connections + transaction combos, right ? Under db4o, you don't really have an object that deals with the transaction since the connection itself has Commit() and Rollback() methods. So, in this case, this would only translate to a connection...

Thanks for the help..
Sami Dalouche

samokk
02-07-2006, 11:41 PM
I actually tried to answer most of my questions on this page :
http://samokk.is-a-geek.com/wordpress/2006/02/07/adding-db4o-oo-database-support-for-springnet-transactions/

I am not sure about everything I wrote. However, the part that I especially do not know anything about is :

However, one thing that I am still unsure about is how connection ressources are disposed. After committing, we do not want to close the session, we just want to tell the PlatformTransactionManager that the resource is now free to reuse for some other thread.


If someone can help..

Mark Pollack
02-12-2006, 05:40 AM
Hi Sami,

Great work in digging into and documenting the main responsibilities of the classes in Spring's transaction abstraction. I don't disagree with your descriptions on your blog. Everything is very much along the lines of what is done in Spring.Java, so any documentation you can find there is very relevant. I'd recommend Professional Java Development with the Spring Framework (http://www.wiley.com/WileyCDA/WileyTitle/productCd-0764574833.html).

You should also take a look at the test area in the sandbox, in particular at TransactionTemplateTests. These are more “integration” style tests that show the usage of the API from the low level, using an instance of PlatformTransactionManager directly, all the way up to declarative transaction demarcation via attributes on a DAO. The bit of Java code you referenced in your blog is already there in C# form on these tests.

The sandbox also has an NHibernate implementation. The iBatis.NET implementation was done a while ago and needs to be integrated with the DbProvider abstraction I'll talk about in a bit. The plan is to get the data access stuff into one of the 1.1 preview releases.

To answer your question, if you look into ConnectionUtils.DisposeConnection it checks to see if there are any ADO.NET transactional resources bound to the current thread (i.e. The connection and transaction objects as encpasulated in the ConnectionHolder object – yea the name is not that accurate). If there are resources bound to the thread then DisposeConnection doesn't actually dispose of the connection, it just marks the transactional resources as “released” for reference counting purposes. ConnectionUtils.DisposeConnection is called in AdoTemplate.Execute. In AdoPlatformTransactionManager there is the method “DoCleanupAfterCompletion” This method is called after Commit or Rollback is called. It unbinds the transactional resources from the thread, and then calls ConnectionUtils.DisposeConnection. This time however, it will actually close the connection since the resources have been unbound from the thread.

Another key abstraction I introduced is the “DbProvider” class along the lines of what is in ADO.NET 2.0. (Not yet complete btw). This acts as a factory for the various classes you need as you walk down the ADO.NET API stack to do your standard database work. This is typically declared as a singleton instance in the application context. Furthermore, it is what is used as the key that binds the ado.net command/tx object pair to the current thread when using the TransactionSynchronizationManager.

The one other thing you need in your recipe is a factory class that will be used to create the main db4o object based not on raw connection strings but the DbProvider abstraction. Sometimes there are additional configuration features you can provide at this level. You can look at the hibernate implementation of LocalSessionFactoryObject for an example.

When implementing support for db4o (which would be great!), you should get the underlying ado.net objects you need via the DbProvider class. This will provide a consistent way to define ado.net connection parameters but more importantly will give you the possibility of having db4o operations and ado.net operations take place within the same transaction. The details of this depend on if you can provide db4o with a ado.net connection/tx pair and if you can get the same from the db4o API. If you can, then the db4oTemplate class can check the TransactionSynchronizationManager for resources under the key “dbProvider” and use the connection/tx objects in there, passing them to db4o instead of db4o creating them for you.

While I'm at it let me describe briefly in my own words the roles of the main classes – this way we can be “on the same page”.

<Platform>Template – The high level API to use a particular data access technology. The methods will typically mimic those on the central class used to perform data access operations. The template takes care of resource management, i.e creating/closing ado.net connections for example. It does not itself create any transactions but it will check for and use any transaction resources that are bound to the current thread. Roughly speaking “Transaction Resources” are whatever is needed by the particular data access technology so that multiple data access operations can be in the same transaction. In the case of ADO.NET, there are two objects, the ado.net connection and ado.net transaction object. In the case of Hibernate is it the hibernate session. You can use the abstract base class ResourceHolderSupport as the basis to store db4o resources.

TransactionSynchronizationManager (TSM): The object that contains the transactional resources bound to the thread. This class is independent of the data access technology. It is the responsibility of the platform specific transaction manager to use the TSM api to bind/unbind transactional resources to the currently executing thread (via thread local).

IPlatformTransactionManager – As you say, this is the main actor – the key abstraction for transaction management. There is an implementation per data access technology and they will initiate a transaction and place “transaction resource” objects into thread local storage via the TSM.

As you point out, for implementors of new data access technologies, most of the hard work to implement this interface with the correct semantics is done for you in AbstractPlatformTransactionManager. (APTM). Subclasses have to implement a series of DoXXX methods marked as abstract in APTM, such as DoBegin, DoCommit, DoResume, etc. At this stage you need to understand ITransactionStatus and ITransactionDefinition.

With these elements in place what remains is how to execute these classes together. You can do it all “by-hand”, that is create an instance of a PlatformTransactionManger and TransactionDefintion and use their APIs directly. If you look at TransactionTemplateTests.ExecuteTransactionManager you will see it in action. However, although this API is not specific to a data access technology you can get rid of this boiler plate code completely by using the TransactionTemplate. However, this is still programmatic style access and there is a great deal of flexibility and power to be gained using declarative transactions in a data access layer. Spring provides an AOP interceptor, i.e. TransactionInterceptor, that can be used to wrap methods within a transaction. The source of metadata that describes the transaction properties, essentially the information in ITransactionDefinition, can come either from the spring xml file, external to the DAO object, or as attributes on the DAO object's methods itself.

Ok, well long reply, hope it helps you. I'll be happy to help you in any way I can as you develop support for db4o.

Cheers,
Mark

samokk
02-19-2006, 02:25 PM
Hi Mark,

thanks a lot for this reply and the book reference !

Concerning the connection cleanup :
It looks like AbstractPlatformTransactionManager has a notion of Synchronizations, that are triggered in order to do the cleanup, etc.
AdoTM doesn't seem to use these, but I have the feeling that it will lead to less code to implement the cleanups that way, instead of overriding the virtual methods from AbstractTM ?

Concerning DbProvider
I don't really understand the link between DbProvider and my stuff. Db4o is a Java/.Net pure-OO database. It does not to an SQL backend or anything, it just persists Plain Old Java Object or Plan Old .Net Objects.

Is DbProvider abstract enough to work even with non-ADO.Net stuff ? For example, there is no notion of a Transaction Object on Db4o, so I can't fill up the Transaction Property in your abstraction...
There is no Command or Connection String either...
Db4o can open connexions using an embedded server (so, the Factory needs a reference to an ObjectServer in addition to a connection string) for example..

So, for the moment, I have implemented my own Factory stuff completly in parallel of the IDbProvider factory...

I think my stuff should be roughly working at the moment, but I am currently facing some problems creating ApplicationContexts. Not sure where the problem comes from (using spring with Mono or x-develop not embedded resources I ask it to embed inside the .dll). So, once I have investigated this issue, I should be able to unit-test the misc. parts and see what works and what doesn't.

Regards,
Sami Dalouche