Transaksi XA menggunakan Spring

Menggunakan server aplikasi J (2) EE telah menjadi norma ketika fitur high-end seperti transaksi, keamanan, ketersediaan, dan skalabilitas adalah wajib. Ada sangat sedikit opsi untuk aplikasi java, yang hanya memerlukan sebagian dari fitur perusahaan ini dan, lebih sering daripada tidak, organisasi menggunakan server J (2) EE yang lengkap. Artikel ini berfokus pada transaksi terdistribusi menggunakan JTA (Java Transaction API) dan akan menguraikan tentang bagaimana transaksi terdistribusi (juga disebut XA) dapat digunakan dalam aplikasi java mandiri, tanpa server JEE, menggunakan framework Spring yang sangat populer dan open source. Implementasi JTA dari JBossTS, Atomikos dan Bitronix.

Sistem pemrosesan transaksi terdistribusi dirancang untuk memfasilitasi transaksi yang menjangkau heterogen, sumber daya sadar-transaksi dalam lingkungan terdistribusi. Dengan menggunakan transaksi terdistribusi, aplikasi dapat menyelesaikan tugas-tugas seperti mengambil pesan dari antrian pesan dan memperbarui satu atau lebih database dalam satu unit transaksional yang mengikuti kriteria ACID (Atomicity, Consistency, Isolation, dan Durability). Artikel ini menguraikan beberapa kasus penggunaan di mana transaksi terdistribusi (XA) dapat digunakan dan bagaimana aplikasi dapat mencapai pemrosesan transaksional menggunakan JTA bersama dengan yang terbaik dari teknologi berkembang biak. Fokus utamanya adalah menggunakan Spring sebagai kerangka kerja server dan bagaimana seseorang dapat mengintegrasikan berbagai implementasi JTA dengan mulus untuk transaksi terdistribusi tingkat perusahaan.

Transaksi XA dan JTA API

Karena cakupan artikel terbatas pada penggunaan implementasi JTA menggunakan kerangka kerja Spring, kami akan secara singkat menyentuh konsep arsitektur pemrosesan transaksi terdistribusi.

Transaksi XA

The X / Open Pemrosesan Transaksi Terdistribusi, dirancang oleh Open Group (vendor konsorsium), mendefinisikan arsitektur komunikasi standar yang memungkinkan beberapa aplikasi untuk berbagi sumber daya yang disediakan oleh pengelola sumber daya ganda, dan memungkinkan pekerjaan mereka untuk dikoordinasikan transaksi global. The XA interface memungkinkan manajer sumber daya untuk bergabung transaksi, untuk melakukan 2PC (dua fase komit) dan untuk memulihkan transaksi di-ragu mengikuti kegagalan.

Gambar 1: Model konseptual lingkungan DTP.

Seperti yang ditunjukkan pada Gambar 1, model memiliki antarmuka berikut:

  1. Antarmuka antara aplikasi dan pengelola sumber daya memungkinkan aplikasi memanggil pengelola sumber daya secara langsung, menggunakan API bawaan pengelola sumber daya atau API XA bawaan bergantung pada apakah transaksi perlu dikelola oleh pemantau transaksi atau tidak.

  2. Antarmuka antara aplikasi dan pemantau transaksi (antarmuka TX), memungkinkan aplikasi memanggil pemantau transaksi untuk semua kebutuhan transaksi seperti memulai transaksi, mengakhiri transaksi, rollback transaksi, dll.

  3. Antarmuka antara pemantau transaksi dan pengelola sumber daya adalah antarmuka XA. Ini adalah antarmuka, yang memfasilitasi protokol komit dua fase untuk mencapai transaksi terdistribusi dalam satu transaksi global.

JTA API

The JTA API , yang didefinisikan oleh Sun Microsystems, adalah API tingkat tinggi yang mendefinisikan interface antara seorang manajer transaksi dan pihak yang terlibat dalam sistem transaksi terdistribusi. JTA terutama terdiri dari tiga bagian:

  • Antarmuka aplikasi tingkat tinggi untuk aplikasi yang membatasi batas transaksi. The UserTransactionantarmuka merangkum ini.

  • Pemetaan Java untuk standar industri X / Open XA protokol (Item # 3 dalam antarmuka X / Open yang tercantum di atas). Ini mencakup antarmuka yang ditentukan dalam javax.transaction.xapaket, yang terdiri dari XAResource, Xid and XAExceptionantarmuka.

  • Antarmuka pengelola transaksi tingkat tinggi yang memungkinkan server aplikasi mengelola transaksi untuk aplikasi pengguna. The TransactionManager, Transaction, Status and Synchronizationinterface cukup banyak menentukan bagaimana server aplikasi mengelola transaksi.

Sekarang kita memiliki ringkasan singkat tentang apa itu standar JTA dan XA, mari kita membahas beberapa kasus penggunaan untuk mendemonstrasikan integrasi implementasi JTA yang berbeda menggunakan Spring, untuk aplikasi java hipotetis kita.

Kasus Penggunaan Kami

Untuk mendemonstrasikan integrasi implementasi JTA yang berbeda dengan Spring, kami akan menggunakan kasus penggunaan berikut:

  1. Perbarui dua sumber daya database dalam transaksi global - Kami akan menggunakan JBossTS sebagai implementasi JTA. Dalam prosesnya, kita akan melihat bagaimana kita dapat secara deklaratif menerapkan semantik transaksi terdistribusi ke POJO sederhana.

  2. Perbarui database dan kirim pesan JMS ke antrean dalam transaksi global - Kami akan mendemonstrasikan integrasi dengan implementasi Atomikos dan Bitronix JTA.

  3. Gunakan pesan JMS dan perbarui database dalam transaksi global - Kami akan menggunakan implementasi Atomikos dan Bitronix JTA. Dalam prosesnya, kita akan melihat bagaimana kita dapat meniru MDP transaksional (Message Driven POJO's).

Kami akan menggunakan MySQL untuk database dan Apache ActiveMQ sebagai penyedia pesan JMS kami untuk kasus penggunaan kami. Sebelum membahas kasus penggunaan, mari kita lihat secara singkat tumpukan teknologi yang akan kita gunakan.

Kerangka pegas

Framework Spring telah memantapkan dirinya sebagai salah satu framework paling berguna dan produktif di dunia Java. Di antara banyak manfaat yang diberikannya, ini juga menyediakan pipa ledeng yang diperlukan untuk menjalankan aplikasi dengan implementasi JTA apa pun. Ini membuatnya unik dalam artian bahwa aplikasi tidak perlu dijalankan dalam wadah JEE untuk mendapatkan keuntungan dari transaksi JTA. Harap dicatat bahwa Spring tidak menyediakan implementasi JTA seperti itu. Satu-satunya tugas dari perspektif pengguna adalah memastikan bahwa implementasi JTA terhubung dengan menggunakan dukungan JTA framework Spring. Inilah yang akan kami fokuskan di bagian berikut.

Transaksi di Musim Semi

Spring menyediakan manajemen transaksi terprogram dan deklaratif menggunakan kerangka kerja transaksi yang ringan. Hal ini memudahkan aplikasi java mandiri untuk memasukkan transaksi (JTA atau non-JTA) baik secara terprogram maupun secara deklaratif. Batasan transaksi terprogram dapat dicapai dengan menggunakan API yang diekspos oleh PlatformTransactionManagerantarmuka dan subkelasnya. Di sisi lain, demarkasi transaksi deklaratif menggunakan solusi berbasis AOP (Aspect Oriented Programming). Untuk artikel ini, kita akan mempelajari demarkasi transaksi deklaratif, karena tidak terlalu mengganggu dan mudah dipahami, menggunakan TransactionProxyFactoryBeankelas. Strategi manajemen transaksi, dalam kasus kami, adalah menggunakan fileJtaTransactionManager, karena kami memiliki banyak sumber daya untuk ditangani. Jika hanya ada satu sumber daya, ada beberapa pilihan bergantung pada teknologi yang mendasarinya dan semuanya mengimplementasikan PlatformTransactionManagerantarmuka. Misalnya, untuk Hibernate, seseorang dapat memilih untuk menggunakan HibernateTransactionManagerdan untuk persistensi berbasis JDO, seseorang dapat menggunakan ekstensi JdoTransactionManager. Ada juga a JmsTransactionManager, yang dimaksudkan untuk transaksi lokal saja.

Kerangka transaksi Spring juga menyediakan alat yang diperlukan untuk aplikasi untuk menentukan perilaku penyebaran transaksi, isolasi transaksi, dan sebagainya. Untuk manajemen transaksi deklaratif, TransactionDefinitionantarmuka menentukan perilaku propagasi, yang sangat mirip dengan atribut CMT EJB. The TransactionAttributeantarmuka memungkinkan aplikasi untuk menentukan pengecualian yang akan menyebabkan rollback dan mana yang akan dilakukan. Ini adalah dua antarmuka penting, yang membuat manajemen transaksi deklaratif sangat mudah digunakan dan dikonfigurasi, dan kita akan melihat saat kita membahas kasus penggunaan kita.

Konsumsi Pesan Asinkron menggunakan Spring

Spring has always supported sending messages using JMS API via its JMS abstraction layer. It employs a callback mechanism, which consists of a message creator and a JMS template that actually sends the message created by the message creator.

Since the release of Spring 2.0, asynchronous message consumption has been made possible using the JMS API. Though Spring provides different message listener containers, for consuming the messages, the one that is mostly suited to both JEE and J2SE environments is the DefaultMessageListenerContainer (DMLC). The DefaultMessageListenerContainer extends the AbstractPollingMessageListenerContainer class and provides full support for JMS 1.1 API. It primarily uses the JMS synchronous receive calls( MessageConsumer.receive()) inside a loop and allows for transactional reception of messages. For J(2)SE environment, the stand-alone JTA implementations can be wired to use the Spring's JtaTransactionManager, which will be demonstrated in the following sections.

The JTA implementations

JBossTS

JBossTS, formerly known as Arjuna Transaction Service, comes with a very robust implementation, which supports both JTA and JTS API. JBossTS comes with a recovery service, which could be run as a separate process from your application processes. Unfortunately, it doesn't support out-of-the box integration with Spring, but it is easy to integrate as we will see in our exercise. Also there is no support for JMS resources, only database resources are supported.

Atomikos Transaction Essentials

Atomikos's JTA implementation has been open sourced very recently. The documentation and literature on the internet shows that it is a production quality implementation, which also supports recovery and some exotic features beyond the JTA API. Atomikos provides out of the box Spring integration along with some nice examples. Atomikos supports both database and JMS resources. It also provides support for pooled connections for both database and JMS resources.

Bitronix JTA

Bitronix's JTA implementation is fairly new and is still in beta. It also claims to support transaction recovery as good as or even better than some of the commercial products. Bitronix provides support for both database and JMS resources. Bitronix also provides connection pooling and session pooling out of the box.

XA Resources

JMS Resources

The JMS API specification does not require that a provider supports distributed transactions, but if the provider does, it should be done via the JTA XAResource API. So the provider should expose its JTA support using the XAConnectionFactory, XAConnection and XASession interfaces. Fortunately Apache's ActiveMQ provides the necessary implementation for handling XA transactions. Our project (see Resources section) also includes configuration files for using TIBCO EMS (JMS server from TIBCO) and one can notice that the configuration files require minimal changes when the providers are switched.

Database Resources

MySQL database provides an XA implementation and works only for their InnoDB engines. It also provides a decent JDBC driver, which supports the JTA/XA protocol. Though there are some restrictions placed on the usage of some XA features, for the purposes of the article, it is good enough.

The Environment

Setup for Databases:

The first database mydb1 will be used for use cases 1 and 2 and will have the following table:

mysql> use mydb1; Database changed mysql> select * from msgseq; +---------+-----------+-------+ | APPNAME | APPKEY | VALUE | +---------+-----------+-------+ | spring | execution | 13 | +---------+-----------+-------+ 1 row in set (0.00 sec)

The second database mydb2 will be used for use case 3 and will have the following table:

mysql> use mydb2; Database changed mysql> select * from msgseq; +---------+------------+-------+ | APPNAME | APPKEY | VALUE | +---------+------------+-------+ | spring | aaaaa | 15 | | spring | allocation | 13 | +---------+------------+-------+ 2 rows in set (0.00 sec)

Setup for JMS provider (for use case 2 and 3)

For creating a physical destination in ActiveMQ, do the following:

  1. Add the following destination to the activmq.xml file under the conf folder of ActiveMQ installation:
  2. Tambahkan baris kode berikut di file jndi.properties untuk menyertakan nama jndi untuk tujuan dan pastikan file tersebut ada di classpath:queue.test.q1=test.q1

Use Case1 - Memperbarui dua database dalam transaksi global menggunakan JBossTS

Gambar 2: UseCase1 memperbarui dua database dalam transaksi global.

Mari kita asumsikan bahwa aplikasi kita memiliki persyaratan di mana ia perlu mempertahankan nomor urut, terkait dengan sebuah peristiwa, dalam dua database yang berbeda ( mydb1 dan mydb2 ), dalam unit kerja transaksional yang sama seperti yang ditunjukkan pada Gambar 2 di atas. Untuk mencapai ini, mari kita tulis metode sederhana di kelas POJO kita, yang memperbarui dua database.

Kode untuk EventHandlerkelas POJO kami terlihat sebagai berikut:

public void handleEvent(boolean fail) throws Exception { MessageSequenceDAO dao = (MessageSequenceDAO) springContext.getBean("sequenceDAO"); int value = 13; String app = "spring"; String appKey = "execution"; int upCnt = dao.updateSequence(value, app, appKey); log.debug(" sql updCnt->" + upCnt); if (springContext.containsBean("sequenceDAO2")) { // this is for use case 1 with JBossTS MessageSequenceDAO dao2 = (MessageSequenceDAO) springContext.getBean("sequenceDAO2"); appKey = "allocation"; upCnt = dao2.updateSequence(value, app, appKey); log.debug(" sql updCnt2->" + upCnt); } ... if (fail) { throw new RuntimeException("Simulating Rollback by throwing Exception !!"); } }