עסקאות XA באמצעות Spring

השימוש בשרת יישומי JE (2) EE היה נורמה כאשר תכונות מתקדמות כמו עסקאות, אבטחה, זמינות ומדרגיות הן חובה. יש מעט מאוד אפשרויות ליישומי Java, הדורשים רק קבוצת משנה של תכונות ארגוניות אלה, ולעתים קרובות יותר, ארגונים הולכים על שרת J (2) EE מלא. מאמר זה מתמקד בעסקאות מבוזרות באמצעות ה- JTA (Java Transaction API) ויפרט כיצד ניתן להשתמש בעסקאות מבוזרות (הנקראות גם XA) ביישום Java עצמאי, ללא שרת JEE, תוך שימוש במסגרת Spring הפופולרית והמקור הפתוח. יישומי JTA של JBossTS, Atomikos ו- Bitronix.

מערכות לעיבוד עסקאות מבוזרות נועדו להקל על עסקאות המשתרעות על משאבים הטרוגניים ומודעים לעסקאות בסביבה מבוזרת. באמצעות עסקאות מבוזרות, יישום יכול לבצע משימות כגון אחזור הודעה מתור הודעות ועדכון מסד נתונים אחד או יותר ביחידת עסקאות אחת העומדת בקריטריונים של חומצה (אטומיות, עקביות, בידוד ועמידות). מאמר זה מתאר כמה ממקרי השימוש בהם ניתן להשתמש בעסקאות מבוזרות (XA) וכיצד יישום יכול להשיג עיבוד עסקאות באמצעות JTA יחד עם מיטב טכנולוגיות הגזע. ההתמקדות העיקרית היא בשימוש באביב כמסגרת שרתים וכיצד ניתן לשלב יישומי JTA שונים בצורה חלקה לעסקאות מבוזרות ברמת הארגון.

עסקאות XA ו- API של JTA

מכיוון שהיקף המאמר מוגבל לשימוש במישומי JTA באמצעות מסגרת האביב, ניגע בקצרה במושגים האדריכליים של עיבוד עסקאות מבוזרות.

עסקאות XA

X / Open עיבוד העסקה מבוזרת, שתוכנן על ידי פתיחת קבוצה (קונסורציום ספק), מגדיר ארכיטקטורת תקשורת סטנדרטית המאפשרת יישומים מרובים לשתף משאבים המסופקים על ידי מנהלי משאבים מרובים, ומאפשר עבודתם כדי להיות מתואמת לתוך עסקות גלובליות. ממשקי ה- XA מאפשרים למנהלי המשאבים להצטרף לעסקאות, לבצע 2PC (התחייבות דו-פאזית) ולשחזר עסקאות בספק בעקבות כשל.

איור 1: מודל רעיוני של סביבת DTP.

כפי שמוצג באיור 1, למודל יש את הממשקים הבאים:

  1. הממשק בין היישום למנהל המשאבים מאפשר לאפליקציה להתקשר ישירות למנהל משאבים, באמצעות ה- API המקורי של מנהל המשאבים או ה- API המקורי של XA, תלוי אם צריך לנהל את העסקה על ידי צג העסקאות או לא.

  2. הממשק בין היישום למוניטור העסקה (ממשק TX), מאפשר ליישום להתקשר למוניטור העסקה לכל צרכי העסקה כמו התחלת עסקה, סיום עסקה, החזרת עסקה וכו '.

  3. הממשק בין מוניטור העסקאות למנהל המשאבים הוא ממשק XA. זהו הממשק המאפשר את פרוטוקול ההתחייבות הדו-פאזי להשגת עסקאות מבוזרות במסגרת עסקה גלובלית אחת.

ממשק API של JTA

ה- API של JTA , המוגדר על ידי Sun Microsystems, הוא ממשק API ברמה גבוהה המגדיר ממשקים בין מנהל עסקאות לבין הגורמים המעורבים במערכת עסקאות מבוזרת. ה- JTA מורכב בעיקר משלושה חלקים:

  • ממשק יישומים ברמה גבוהה ליישום לתיחום גבולות העסקה. UserTransactionהממשק מתמצת זה.

  • מיפוי Java של פרוטוקול X / Open XA הסטנדרטי בתעשייה (פריט מס '3 בממשקי X / Open הרשומים לעיל). זה כולל את הממשקים שהוגדרו javax.transaction.xaבחבילה, הכוללים XAResource, Xid and XAExceptionממשקים.

  • ממשק מנהל עסקאות ברמה גבוהה המאפשר לשרת יישומים לנהל עסקאות עבור יישום משתמש. TransactionManager, Transaction, Status and Synchronizationממשקים פחות או יותר להגדיר איך שרת היישומים מנהלת עסקאות.

כעת, כשיש לנו סיכום קצר של תקני JTA ו- XA, נעבור על כמה מקרי שימוש כדי להדגים את שילובם של יישומי JTA שונים באמצעות Spring, ליישום Java ההיפותטי שלנו.

מקרי השימוש שלנו

כדי להדגים את שילובם של יישומי JTA שונים עם Spring, נשתמש במקרי השימוש הבאים:

  1. עדכן שני משאבי מסדי נתונים בעסקה גלובלית - אנו נשתמש ב- JBossTS כמימוש JTA. בתהליך נראה כיצד אנו יכולים להחיל סמנטיקה של עסקאות מבוזרות באופן הצהרתי על POJO פשוטים.

  2. עדכן מסד נתונים ושלח הודעת JMS לתור בעסקה גלובלית - נדגים אינטגרציה עם יישומי Atomikos ו- Bitronix JTA.

  3. צרכו הודעת JMS ועדכנו מסד נתונים בעסקה גלובלית - נשתמש ביישומי Atomikos ו- Bitronix JTA. בתהליך נראה כיצד אנו יכולים לחקות MDP עסקאות (Message Driven POJO).

אנו נשתמש ב- MySQL עבור מסדי הנתונים וב- Apache ActiveMQ כספק העברת ההודעות JMS שלנו למקרי השימוש שלנו. לפני שנעבור על מקרי השימוש, הבה נבחן בקצרה את ערימת הטכנולוגיה בה אנו נשתמש.

מסגרת אביבית

מסגרת האביב ביססה את עצמה כאחת המסגרות השימושיות והפרודוקטיביות ביותר בעולם ג'אווה. בין היתרונות הרבים שהוא מספק, הוא גם מספק את הצנרת הדרושה להפעלת יישום עם כל יישום JTA. זה עושה את זה ייחודי במובן זה שאפליקציה לא צריכה לרוץ במיכל JEE כדי לקבל את היתרונות של עסקאות JTA. שימו לב כי אביב אינו מספק כל יישום JTA ככזה. המשימה היחידה מנקודת מבט המשתמש היא לוודא כי יישום JTA מחובר לשימוש בתמיכת JTA של מסגרת האביב. על זה נתמקד בסעיפים הבאים.

עסקאות באביב

אביב מספק ניהול עסקאות פרוגרמטי וגם הצהרתי תוך שימוש במסגרת עסקאות קלת משקל. זה מקל על יישומי Java עצמאיים לכלול עסקאות (JTA או שאינן JTA) באופן פרוגרמטי או הצהרתי. ניתן לבצע את תיחום העסקה הפרוגרמטית באמצעות ה- API שנחשף על ידי PlatformTransactionManagerהממשק ותתי המחלקות שלו. מצד שני, תיחום העסקה הצהרתי משתמש בפתרון מבוסס AOP (Aspect Oriented Programming). למאמר זה נחקור את תיחום העסקה ההצהרתית, מכיוון שהוא פחות פולשני וקל להבנה באמצעות TransactionProxyFactoryBeanהכיתה. אסטרטגיית ניהול העסקאות, במקרה שלנו, היא להשתמש ב-JtaTransactionManager, מכיוון שיש לנו מספר משאבים להתמודד איתם. אם יש רק משאב יחיד, יש כמה אפשרויות בהתאם לטכנולוגיה הבסיסית וכולן מיישמות את PlatformTransactionManagerהממשק. לדוגמא, במצב שינה, ניתן לבחור להשתמש HibernateTransactionManagerולתמדה מבוססת JDO, ניתן להשתמש ב- JdoTransactionManager. יש גם א JmsTransactionManager, המיועד לעסקאות מקומיות בלבד.

מסגרת העסקאות של Spring מספקת את הכלים הדרושים ליישומים להגדרת התנהגות התפשטות העסקאות, בידוד העסקאות וכן הלאה. לניהול עסקאות הצהרתי, TransactionDefinitionהממשק מציין את התנהגות ההפצה, הדומה מאוד למאפייני EJB CMT. TransactionAttributeהממשק מאפשר יישום כדי לציין אילו חריגים יגרמו החזרה ואלו יהיו מחויבים. אלה שני הממשקים המכריעים, אשר הופכים את ניהול העסקה ההצהרתית לקלה מאוד לשימוש ולהגדרה, ונראה כשאנחנו עוברים את מקרי השימוש שלנו.

צריכת הודעות אסינכרונית באמצעות אביב

אביב תמיד תמכה בשליחת הודעות באמצעות JMS API באמצעות שכבת ההפשטה של ​​JMS. היא מפעילה מנגנון התקשרות חוזרת, המורכב מיוצר הודעות ותבנית JMS השולחת בפועל את ההודעה שיצר יוצר ההודעות.

מאז שחרורו של אביב 2.0 התאפשרה צריכת הודעות אסינכרוניות באמצעות ממשק ה- API של JMS. למרות ש- Spring מספק מכולות שונות של מאזינים להודעות, לצורך צריכת ההודעות, זה שמתאים בעיקר לסביבות JEE ו- J2SE הוא ה- DefaultMessageListenerContainer(DMLC). התוכנית DefaultMessageListenerContainerמרחיבה את AbstractPollingMessageListenerContainerהכיתה ומספקת תמיכה מלאה ב- API של JMS 1.1. זה בעיקר משתמש בשיחות הסינכרוניות לקבלת JMS ( MessageConsumer.receive()) בתוך לולאה ומאפשר קבלת הודעות בעסקאות. עבור סביבת J (2) SE, ניתן לחבר את יישומי ה- JTA העצמאים לשימוש במעיין JtaTransactionManager, אשר יודגם בסעיפים הבאים.

יישומי JTA

JBossTS

JBossTS, שנקרא בעבר שירות עסקאות Arjuna, מגיע עם יישום חזק מאוד, התומך ב- JTA ו- JTS API. JBossTS מגיע עם שירות התאוששות, שיכול להיות מופעל כתהליך נפרד מתהליכי היישום שלך. למרבה הצער, הוא אינו תומך בשילוב מחוץ לקופסה עם אביב, אך קל לשילוב כפי שנראה בתרגיל שלנו. כמו כן, אין תמיכה במשאבי JMS, רק במשאבי מסד נתונים נתמכים.

יסודות העסקה של Atomikos

יישום ה- JTA של Atomikos נפתח לאחרונה ממש לאחרונה. התיעוד והספרות באינטרנט מראים שמדובר ביישום איכות ייצור, שתומך גם בשחזור ובכמה מאפיינים אקזוטיים מעבר ל- JTA API. Atomikos מספקת מהקופסה שילוב האביב יחד עם כמה דוגמאות נחמדות. Atomikos תומך הן במשאבי מסד נתונים והן ב- JMS. הוא גם מספק תמיכה בחיבורים מאוגדים הן עבור משאבי מסד נתונים והן עבור JMS.

ביטרוניקס JTA

יישום ה- JTA של ביטרוניקס הוא חדש למדי והוא עדיין בגרסת בטא. כמו כן, היא טוענת כי היא תומכת בהחלמת עסקאות טובה או אפילו טובה יותר מחלק מהמוצרים המסחריים. Bitronix מספקת תמיכה הן במשאבי מסד נתונים והן ב- JMS. Bitronix מספקת גם איגום חיבורים ואיגוד הפעלות מחוץ לקופסה.

משאבי XA

משאבי JMS

מפרט ה- JMS API אינו מחייב שספק תומך בעסקאות מבוזרות, אך אם הספק עושה זאת, יש לעשות זאת באמצעות ה- JTA XAResource API. לכן על הספק לחשוף את תמיכת ה- JTA שלו באמצעות XAConnectionFactory, XAConnection and XASessionהממשקים. למרבה המזל ה- ActiveMQ של אפאצ'י מספק את היישום הדרוש לטיפול בעסקאות XA. הפרויקט שלנו (ראה סעיף משאבים) כולל גם קבצי תצורה לשימוש ב- TIBCO EMS (שרת JMS מ- TIBCO) ואפשר להבחין כי קבצי התצורה דורשים שינויים מינימליים בעת החלפת הספקים.

משאבי מסד נתונים

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. הוסף את שורת הקוד הבאה בקובץ jndi.properties כדי לכלול את שם jndi עבור היעד וודא שהקובץ נמצא בכיתה:queue.test.q1=test.q1

השתמש ב- Case1 - עדכון שני מסדי נתונים בעסקה גלובלית באמצעות JBossTS

איור 2: UseCase1 מעדכן שני מסדי נתונים בעסקה גלובלית.

נניח שליישום שלנו יש דרישה בה הוא צריך להחזיק מספר רצף, המשויך לאירוע, בשני מאגרי מידע שונים ( mydb1 ו- mydb2 ), באותה יחידת עבודה טרנזאקטיבית כפי שמוצג באיור 2 לעיל. כדי להשיג זאת, בואו נכתוב שיטה פשוטה בכיתת POJO שלנו, שמעדכנת את שני מסדי הנתונים.

הקוד EventHandlerלשיעור POJO שלנו נראה כך:

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 !!"); } }