-
Notifications
You must be signed in to change notification settings - Fork 0
wimdetroyer/Distributed-transactions-in-Spring-with-and-without-XA-mirror
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html><head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><title>Distributed transactions in Spring with and without XA</title> <style type="css"> body, td, pre { font-size: x-small; font-family: Verdana, Arial, Helvetica, sans-serif; color: #000; font-size: small; font-family: Verdana, Arial, Helvetica, sans-serif; color: #000; } code, pre { margin: 0; padding: 0; } </style> <h1>Distributed transactions in Spring with and without XA</h1> <h2>The sample code</h2> <p>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 <a href="http://q4e.googlecode.com/svn/trunk/updatesite">Q4E update site</a> 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 <code>.classpath</code> and <code>.project</code> 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 <code>pom.xml</code> to create a classpath for the build.</p> <p>All of the samples use Spring to configure the underlying infrastructure (databases and so on), and the configuration is in <code>src/main/resources/META-INF/spring/*.xml</code>, 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).</p> <p>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).</p> <h3>Project <code>atomikos-db</code></h3> <p>This is the XA/JTA example, included for the sake of completeness. It uses Atomikos for the JTA implementation and Apache Derby for the <code>XADataSource</code>. The tests show two data sources being updated in the same transaction and then rolling back together.</p> <p>In the sample code, some <code>XADataSource</code> instances are configured like this:</p> <pre> <code><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> </pre> </code> <p>The <code>AtomikosDataSourceFactoryBean</code> 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 <code>DerbyDataSourceFactoryBean</code> is provided also for test purposes as a factory for the <code>XADataSource</code> 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 <code>XADataSource</code> provided by the database vendor (Apache Derby).</p> <p>The transaction manager is configured like this:</p> <pre> <code><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> </pre> </code> <h3>Project <code>shared-jms-db</code></h3> <p>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 <code>SynchronousMessage*Tests</code>unit test .</p> <p>The <code>JmsTransactionAwareDataSourceProxy</code> that is used to synchronize the JMS <code>Session</code> with the Spring transaction is an extension of the Spring <code>TransactionAwareDataSourceProxy</code>. 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.</p> <p>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 <code>vm://</code>). 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 <code>async=false</code> to make the shared resource pattern work. The embedded brokers in the various processes that comprise a system communicate through network connectors.</p> <p>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:</p> <ul> <li>The embedded broker with <code>async=false</code> so that the JMS persistence happens in the same thread as the main transaction.</li> <li>The use of the <code>JDBCPersistenceAdapter</code> in the broker, where the injected <code>DataSource</code> is a special proxy that ensures that transaction boundaries are respected.</li> <li>In a distributed system, unlike in the samples, synonyms (or equivalent) would have to be used to link the ActiveMQ data to the business data in the RDBMS platform.</li> <li>A distributed system would also have to allow all the embedded brokers to communicate with each other using a network connector. This is standard practice for large messaging installations anyway, but to use the shared resource pattern it is mandatory. See the <a href="http://activemq.apache.org/topologies.html">ActiveMQ topologies documentation</a> for more details.</li> </ul> <h3>Project <code>best-jms-db</code></h3> <p>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 <code>AsynchronousMessageTriggerAndRollbackTests</code>. There is also a version of the <code>SynchronousMessageTriggerAndRollbackTests</code> from the <code>shared-jms-db</code> sample showing that the synchronous example also works just fine with this pattern.</p> <h3>Project <code>best-db-db</code></h3> <p>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.</p> </body> </html>
About
mirror of the source code in Dave Syers Javaworld article about "Distributed transactions in Spring with and without XA"
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published