2017-01-26 10 views
10

हमारे पास एक ऐसा एप्लिकेशन है जिसमें कई इकाई वर्ग हैं जिनके लिए दो टेबल होना चाहिए। सारणी समान हैं, केवल अंतर ही नाम है। एसओ पर यहां पेश किए गए सामान्य समाधान विरासत (एक मैप किए गए सुपरक्लास और एक टेबल-प्रति-श्रेणी रणनीति) या विभिन्न मैपिंग के साथ दो दृढ़ता इकाइयों का उपयोग करना है। हम बाद के समाधान का उपयोग करते हैं और एप्लिकेशन इस दृष्टिकोण के शीर्ष पर बनाया गया है, इसलिए इसे अब दिया गया माना जाता है।क्या एक्सए के बिना लेनदेन में दो एमएसएसएलएल दृढ़ता इकाइयां हो सकती हैं?

ईजेबी विधियां हैं जो दृढ़ता संदर्भ दोनों पर अपडेट करेगी और एक लेनदेन के भीतर ऐसा करना चाहिए। दोनों दृढ़ता संदर्भों में एक ही डेटा स्रोत होता है, जो एक Microsoft SQL सर्वर डेटाबेस (2012 संस्करण) के लिए एक एक्सए-सक्षम कनेक्शन है। संदर्भों के बीच एकमात्र अंतर यह है कि किसी इकाई इकाई के लिए तालिका नामों को बदलने के लिए एक मैपिंग एक्सएमएल है और इस प्रकार उन तालिकाओं पर काम करता है।

आर्किटेक्चर लीड में से एक एक्सए लेनदेन को समाप्त करना चाहता है, क्योंकि वे डेटाबेस पर एक महत्वपूर्ण ओवरहेड का कारण बनते हैं और स्पष्ट रूप से उन प्रश्नों के लॉगिंग और विश्लेषण भी करते हैं जिन्हें अधिक कठिन निष्पादित किया जाता है, संभवतः कुछ तैयार कथन कैशिंग को रोकना । मुझे सभी विवरण नहीं पता, लेकिन कई अनुप्रयोगों के लिए हमने एक्सए को खत्म करने में कामयाब रहा है। इस के लिए, हालांकि, हम वर्तमान में दो दृढ़ता संदर्भों के कारण नहीं कर सकते हैं।

क्या इस स्थिति में एक्सए के बिना लेनदेन के तरीके में दोनों संदर्भों के अपडेट प्राप्त करने के लिए इस स्थिति में कोई तरीका है? यदि हां, तो कैसे? यदि नहीं, तो क्या कुछ वास्तुकला या कॉन्फ़िगरेशन परिवर्तन दो तालिकाओं के लिए उप-वर्गों को चालू किए बिना एक दृढ़ता संदर्भ का उपयोग करने के लिए संभव है?

मैं इन सवालों के बारे में पता कर रहा हूँ: Is it possible to use more than one persistence unit in a transaction, without it being XA? और XA transaction for two phase commit

डुप्लीकेट के रूप में इस बंद करने के लिए, ध्यान दें कि स्थितियों अलग हैं लेने के मतदान से पहले। हम केवल पहले प्रश्न में पढ़ने की स्थिति में नहीं हैं, दोनों संदर्भ एक ही डेटाबेस पर काम करते हैं, हम विशेष रूप से एमएसएसक्यूएल का उपयोग कर रहे हैं और हम ग्लासफ़िश पर हैं, वेबलॉग नहीं।

+0

यदि दो दृढ़ता इकाइयां एक ही डेटास्रोत का उपयोग कर रही हैं तो आपको XA –

+0

@SteveC की आवश्यकता नहीं होनी चाहिए, उन्हें पूल से अपना कनेक्शन मिल जाएगा, इसलिए मुझे उन्हें एक ही कनेक्शन रखने के लिए मजबूर करने का कोई तरीका नहीं दिख रहा है (और इस प्रकार लेनदेन) या जेपीए वास्तव में इसका प्रबंधन कैसे करेगा। –

+0

मैं उम्मीद करता हूं कि वे दोनों एक ही जेटीए लेनदेन में भाग लेंगे ... –

उत्तर

5

कुछ प्रयोग करने के बाद, मैंने पाया है कि वास्तव में दो स्थिरता इकाइयां हैं जो एक कंटेनर-प्रबंधित लेनदेन के भीतर गैर-एक्सए संसाधनों का उपयोग करती हैं। हालांकि, यह कार्यान्वयन-निर्भर हो सकता है। टीएल; नीचे डीआर।

यदि किसी एक से अधिक संसाधन लेन-देन में भाग लेते हैं तो जेटीए को एक्सए संसाधनों की आवश्यकता होनी चाहिए। यह वितरित लेनदेन की अनुमति के उद्देश्य से एक्स/ओपन एक्सए का उपयोग करता है, उदाहरण के लिए एकाधिक डेटाबेस, या डेटाबेस और जेएमएस कतार में। स्पष्ट रूप से कुछ अनुकूलन है (यह ग्लासफ़िश-विशिष्ट हो सकता है, मुझे यकीन नहीं है) जो अंतिम प्रतिभागी को गैर-एक्सए होने की अनुमति देता है। मेरे उपयोग-मामले में, हालांकि, दोनों दृढ़ता इकाइयां एक ही डेटाबेस के लिए हैं (लेकिन कुछ संभावित ओवरलैप के साथ तालिकाओं का एक अलग सेट) और दोनों गैर-एक्सए हैं। इसका मतलब है कि जब हम दूसरा संसाधन XA का समर्थन नहीं करते हैं तो हम एक अपवाद को फेंकने की उम्मीद करेंगे।

मान लीजिए यह हमारे persistence.xml

है
<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="2.0" 
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> 
    <persistence-unit name="playground" transaction-type="JTA"> 
     <provider>org.hibernate.ejb.HibernatePersistence</provider> 
     <jta-data-source>jdbc/playground</jta-data-source> 
     <properties> 
      <property name="hibernate.dialect" value="be.dkv.hibernate.SQLServer2012Dialect" /> 
      <property name="hibernate.hbm2ddl.auto" value="update" /> 
      <property name="hibernate.show_sql" value="true" /> 
     </properties> 
    </persistence-unit> 
    <persistence-unit name="playground-copy" transaction-type="JTA"> 
     <provider>org.hibernate.ejb.HibernatePersistence</provider> 
     <jta-data-source>jdbc/playground</jta-data-source> 
     <mapping-file>META-INF/orm-playground-copy.xml</mapping-file> 
     <properties> 
      <property name="hibernate.dialect" value="be.dkv.hibernate.SQLServer2012Dialect" /> 
      <property name="hibernate.hbm2ddl.auto" value="update" /> 
      <property name="hibernate.show_sql" value="true" /> 
     </properties> 
    </persistence-unit> 
</persistence> 

दो हठ इकाइयों, नाम playground के साथ एक, नाम playground-copy के साथ अन्य रहे हैं। उत्तरार्द्ध में एक ओआरएम मैपिंग फ़ाइल है लेकिन यह बिंदु के अलावा थोड़ा सा है। महत्वपूर्ण यह है कि दोनों के पास <jta-data-source> निर्दिष्ट है।

एप्लिकेशन सर्वर (इस मामले में ग्लासफ़िश) में, हमारे पास एक जेडीबीसी कनेक्शन पूल होगा, जिसमें एक जेडीबीसी संसाधन playground है जो इस पूल का उपयोग करता है।

connection pool and resource

अब दो हठ संदर्भों एक EJB में इंजेक्ट किया जाता है, और एक विधि कहा जाता है कि एक कंटेनर से प्रबंधित लेन-देन के भीतर माना जाता है, आप चीजों को इस तरह देखने के लिए उम्मीद थी, तो।

persistence unit connections

दोनों दृढ़ता संदर्भों में एक ही डेटा स्रोत का उपयोग, लेकिन न तो लेन-देन प्रबंधक और न ही जेपीए परत वास्तव में उस के बारे में ज्यादा ध्यान देना चाहिए। आखिरकार, उनके पास अलग-अलग डेटा स्रोत हो सकते हैं। चूंकि डेटा स्रोत को किसी भी कनेक्शन पूल द्वारा समर्थित किया जाता है, इसलिए आप दोनों इकाइयों को अपना कनेक्शन प्राप्त करने की अपेक्षा करेंगे। एक्सए कार्य को लेनदेन के तरीके से संचालित करने की अनुमति देगा, क्योंकि एक्सए-सक्षम संसाधन 2-चरण प्रतिबद्धता लागू करेंगे।

हालांकि, गैर-एक्सए कार्यान्वयन (और कुछ वास्तविक दृढ़ता कार्य करने वाले) के साथ कनेक्शन पूल को इंगित करने वाले डेटा स्रोत के साथ उपरोक्त प्रयास करते समय, कोई अपवाद नहीं था और सबकुछ ठीक काम करता था! एमएसएसक्यूएल सर्वर में एक्सए समर्थन भी अक्षम कर दिया गया था और एक्सए चालक का उपयोग करने का प्रयास करने के परिणामस्वरूप त्रुटि हो गई थी, इसलिए ऐसा नहीं है कि मैं गलती से बिना एक्सए के एक्सए का उपयोग कर रहा था।

डीबगर के साथ कोड में जाकर पता चला कि दोनों दृढ़ता संदर्भ, अलग-अलग इकाई प्रबंधकों (जैसा कि उन्हें करना चाहिए) वास्तव में एक ही कनेक्शन का उपयोग करते थे। कुछ और खुदाई से पता चला कि कनेक्शन को एक्सए लेनदेन में नहीं रखा गया था, और जेडीबीसी स्तर पर एक ही लेनदेन पहचानकर्ता था। तो स्थिति यह बन गया:

shared connection

मैं केवल यह मान सकते हैं जेपीए प्रदाता एक ही कनेक्शन का उपयोग करने के कई इकाइयों एक ही लेन-देन के लिए बनाई गई हैं अगर एक अनुकूलन है। तो, यह ठीक क्यों होगा? जेडीबीसी स्तर पर लेनदेन एक कनेक्शन पर किया जाता है। जहां तक ​​मुझे पता है, जेडीबीसी स्पेक एक कनेक्शन पर कई लेनदेन चलाने की विधि प्रदान नहीं करता है। इसका मतलब है कि यदि एक दृढ़ता संदर्भ के लिए काम किया जाता है, तो प्रतिबद्धता दूसरे के लिए भी होती है।

लेकिन वास्तव में यह है क्यों यह काम करता है। एक वितरित लेनदेन के लिए प्रतिबद्ध बिंदु कार्य करना चाहिए जैसे कि सभी हिस्सों में एक संपूर्ण रूप है (मतदान चरण में सभी मतदान "हां" मानते हैं)। इस मामले में, दोनों दृढ़ता संदर्भ एक ही कनेक्शन पर परिचालन कर रहे हैं, इसलिए वे पूरी तरह से काम की एक इकाई हैं। चूंकि लेनदेन कंटेनर द्वारा प्रबंधित किया जाता है, वैसे भी इसके लिए तत्काल पहुंच नहीं है, जिसका अर्थ है कि आप एक संदर्भ करने के लिए आगे नहीं बढ़ सकते हैं, न कि दूसरे। और वास्तव में लेनदेन के साथ पंजीकरण करने के लिए केवल एक कनेक्शन के साथ, यह एक्सए नहीं होना चाहिए, क्योंकि इसे लेनदेन प्रबंधक के दृष्टिकोण से वितरित नहीं माना जाता है।

ध्यान दें कि यह दृढ़ता संदर्भों के इलाके का उल्लंघन नहीं करता है। डेटाबेस परिणामों से किसी इकाई को दोनों संदर्भों में एक अलग ऑब्जेक्ट में प्राप्त करना। वे अभी भी एक दूसरे से स्वतंत्र रूप से काम कर सकते हैं, जैसे वे अलग कनेक्शन के साथ करेंगे। उपरोक्त आरेख में, एक ही प्राथमिक कुंजी के साथ उसी प्रकार की प्राप्त इकाइयां समान डेटाबेस पंक्ति का प्रतिनिधित्व करती हैं, लेकिन अलग-अलग ऑब्जेक्ट्स उनके संबंधित इकाई प्रबंधकों द्वारा प्रबंधित की जाती हैं।

यह सत्यापित करने के लिए कि यह वास्तव में जेपीए प्रदाता द्वारा कुछ अनुकूलन है, मैंने दूसरा कनेक्शन पूल (उसी डेटाबेस में) और एक अलग जेडीबीसी संसाधन बनाया है, इसे दूसरी दृढ़ता इकाई के लिए सेट किया है और परीक्षण किया है। यह उम्मीद अपवाद में परिणाम:

Caused by: java.sql.SQLException: Error in allocating a connection. 
Cause: java.lang.IllegalStateException: Local transaction already has 1 non-XA Resource: cannot add more resources. 

आप दो JDBC संसाधन बनाने, लेकिन एक ही कनेक्शन पूल करने के लिए दोनों इंगित करते हैं, तो फिर यह सिर्फ ठीक काम करता है।यह स्पष्ट रूप से कक्षा com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource का उपयोग करते समय भी काम करता है, यह पुष्टि करते हुए कि यह एक ही डेटा स्रोत (जो ग्लासफ़िश पूलिंग को पराजित करेगा) के लिए दो बार गलती से एक ही कनेक्शन प्राप्त करने के बजाय जेपीए स्तर पर एक अनुकूलन है। एक एक्सए डेटा स्रोत का उपयोग करते समय, यह वास्तव में एक एक्सए-सक्षम कनेक्शन होगा, लेकिन जेपीए प्रदाता अभी भी दृढ़ता संदर्भ दोनों के लिए एक ही उपयोग करेगा। केवल अलग पूल का उपयोग करते समय यह वास्तव में दो पूरी तरह से अलग एक्सए-सक्षम कनेक्शन होगा और अब आपको उपरोक्त अपवाद नहीं मिलेगा।

तो, कैच क्या है? सबसे पहले, मुझे जेपीए या जेटीए चश्मा में इस व्यवहार का वर्णन (या अनिवार्य) कुछ भी नहीं मिला है। इसका मतलब है कि यह शायद एक कार्यान्वयन-विशिष्ट अनुकूलन है। एक अलग जेपीए प्रदाता, या यहां तक ​​कि एक अलग संस्करण में ले जाएं, और यह अब काम नहीं कर सकता है।

दूसरा, डेडलॉक्स प्राप्त करना संभव है। यदि आप उपरोक्त उदाहरण में इकाई को दोनों संदर्भों में लाते हैं, तो इसे एक में बदलें और फ्लश करें, यह ठीक है। इसे एक संदर्भ में लाएं, फ्लश विधि को कॉल करें और फिर इसे दूसरे में लाने का प्रयास करें, और आपके पास डेडलॉक हो सकता है। यदि आप पठन-रहित लेनदेन अलगाव की अनुमति देते हैं, तो आप इससे बचेंगे लेकिन एक संदर्भ में जो आप देखेंगे, उस पर निर्भर करेगा जब आप इसे दूसरे में फ्लश के सम्मान के साथ लाएंगे। तो मैन्युअल फ्लश कॉल मुश्किल हो सकता है।

संदर्भ के लिए, ग्लासफ़िश संस्करण का उपयोग 3.1.2.2 था। जेपीए प्रदाता हाइबरनेट संस्करण 3.6.4.Final था।


टी एल; डॉ

हाँ, आप एक JavaEE कंटेनर से प्रबंधित लेन-देन में एक ही गैर-XA संसाधन के साथ दो हठ संदर्भों का उपयोग कर सकते हैं, और एसिड गुण संरक्षित कर रहे हैं। हालांकि, यह एक हाइबरनेट ऑप्टिमाइज़ेशन की संभावना है, जब एक ही डेटा स्रोत के साथ एक ही लेनदेन के लिए एकाधिक EntityManagers बनाए जाते हैं। चूंकि यह जेपीए या जेटीए चश्मा द्वारा अनिवार्य नहीं लगता है, इसलिए आप जेपीए कार्यान्वयन, संस्करण या एप्लिकेशन सर्वर पर इस व्यवहार पर भरोसा नहीं कर सकते हैं। तो परीक्षण करें और पूर्ण पोर्टेबिलिटी की उम्मीद न करें।

+1

क्या आप सुनिश्चित हैं कि दोनों इकाई प्रबंधकों के दृढ़ता संदर्भ (सत्र) ठीक से बंद हैं? यदि नहीं, तो आप थोड़ी देर के बाद स्मृति के बिना समाप्त हो सकते हैं या पुराने डेटा के साथ काम कर सकते हैं यदि बाद के अनुरोधों में एक दृढ़ता संदर्भ उदाहरण का पुन: उपयोग किया जाता है। –

+0

@DraganBozanovic अच्छा बिंदु। मैं मानता हूं (संभवतः गलत तरीके से) कि प्रयास के साथ इसे हाइबरनेट देवों को स्पष्ट रूप से पता लगाना चाहिए कि क्या दो संदर्भ समान कंटेनर लेनदेन में हैं और उन्हें एक कनेक्शन साझा करना है, इसे ध्यान में रखा गया है। क्या इसका परीक्षण करने का कुछ अच्छा तरीका होगा? एक बार कॉल छोड़ने के बाद मैं लेनदेन संदर्भ से बाहर हूं, इसलिए मेरे पास वास्तव में डीबग करने के लिए कुछ नहीं है। मुझे लगता है कि मैं हाइबरनेट स्रोत –

+0

ला सकता हूं शुरुआत के लिए आप केवल इकाई प्रबंधकों (जेएमटर या इसी तरह के माध्यम से) दोनों अनुरोधों को आग लगा सकते हैं और एक प्रोफाइलर के माध्यम से जांच सकते हैं कि स्मृति खपत बढ़ रही है या नहीं। –

संबंधित मुद्दे