The sample code is packaged as a set of Eclipse / Maven projects. All the projects should work as standalones; there are no dependencies between projects and no parent POM for the Maven metadata. I used Q4E to provide the Maven support in Eclipse, so if you have that you are set. (Go to the Q4E update site if you need to install it.) If you don't want to use Q4E, and you still want to use Eclipse, you can just delete the .classpath
and .project
files from each project and use your favorite Maven support to re-create the Eclipse metadata. Remember to add the Spring project nature back if you do that. If you don't want to use Maven at all, you need to use the dependency information in the pom.xml
to create a classpath for the build.
All of the samples use Spring to configure the underlying infrastructure (databases and so on), and the configuration is in src/main/resources/META-INF/spring/*.xml
, with annotations for dependency injection. They also all use embedded database and messaging instances, so you don't need to start any external processes. This is not intended for production use, and I have heard reports of XA problems with several open source RDBMS platforms, including Apache Derby (used in the XA samples without any problems, but this is not an exhaustive test).
Unit tests are used to show the features of each pattern in action. To run them in Eclipse just right click (on a test or on the project) and choose Run As->JUnit Test. All tests should pass. Most use the integration test support from Spring to roll back a transaction automatically, so that the tests can make assertions about the success of the most common failure scenario (full rollback).
atomikos-db
This is the XA/JTA example, included for the sake of completeness. It uses Atomikos for the JTA implementation and Apache Derby for the XADataSource
. The tests show two data sources being updated in the same transaction and then rolling back together.
In the sample code, some XADataSource
instances are configured like this:
<bean id="dataSource" class="com.springsource.open.db.AtomikosDataSourceFactoryBean">
<property name="uniqueResourceName" value="data-source"/>
<property name="xaDataSource">
<bean class="test.jdbc.datasource.DerbyDataSourceFactoryBean">
<property name="databaseName" value="derbydb" />
</bean>
</property>
</bean>
The AtomikosDataSourceFactoryBean
is a simple factory bean that we provide for the sample just to make it easy to configure and handle the life cycle of an Atomikos data source. The DerbyDataSourceFactoryBean
is provided also for test purposes as a factory for the XADataSource
provided by Apache Derby. (Setup details for Oracle, MySQL, DB2, and other RDBMSs are in the Atomikos documentation). The main point here is that we are using a connection pool provided by the JTA vendor (Atomikos) and a special XADataSource
provided by the database vendor (Apache Derby).
The transaction manager is configured like this:
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown" value="true"/>
<property name="transactionTimeout" value="600"/>
</bean>
</property>
<property name="userTransaction">
<bean class="com.atomikos.icatch.jta.UserTransactionImp" />
</property>
</bean>
shared-jms-db
This is the project showing a shared resource approach to message-driven database updates. The important features of the configuration are described in the article text. The main entry point is the SynchronousMessage*Tests
unit test .
The JmsTransactionAwareDataSourceProxy
that is used to synchronize the JMS Session
with the Spring transaction is an extension of the Spring TransactionAwareDataSourceProxy
. It might not be the best way to implement this pattern, but it is the quickest and most direct that works for the purpose of this example.
One other thing that is worth mentioning is the use of ActiveMQ with an embedded broker to keep the test self-contained (the broker URL starts with vm://
). A distributed system would probably have more than one participant in the messaging, and multiple brokers would be needed, but they should all be embedded and used with async=false
to make the shared resource pattern work. The embedded brokers in the various processes that comprise a system communicate through network connectors.
It might help if we summarize the ActiveMQ specific features of this pattern, just to be clear what we have done. The main points to note are:
async=false
so that the JMS persistence happens in the same thread as the main transaction.JDBCPersistenceAdapter
in the broker, where the injected DataSource
is a special proxy that ensures that transaction boundaries are respected.best-jms-db
This is the project showing a Best Efforts 1PC approach to message-driven database updates. The important features of the asynchronous pattern are described in the text above. The main entry point is the unit test AsynchronousMessageTriggerAndRollbackTests
. There is also a version of the SynchronousMessageTriggerAndRollbackTests
from the shared-jms-db
sample showing that the synchronous example also works just fine with this pattern.
best-db-db
This is the project showing a Best Efforts 1PC approach to linked database updates. The important features are described in the article text. The main entry point is the unit test MultipleDatasourceTests.