क्या आपको कक्षाओं और / या उनके तरीकों @Transactional
में जगह देनी चाहिए DAO
या डीएओ ऑब्जेक्ट्स का उपयोग करके कॉल करने वाली सेवा कक्षाओं को एनोटेट करना बेहतर है? या क्या यह दोनों "परतों" की व्याख्या करने के लिए समझ में आता है?
क्या आपको कक्षाओं और / या उनके तरीकों @Transactional
में जगह देनी चाहिए DAO
या डीएओ ऑब्जेक्ट्स का उपयोग करके कॉल करने वाली सेवा कक्षाओं को एनोटेट करना बेहतर है? या क्या यह दोनों "परतों" की व्याख्या करने के लिए समझ में आता है?
जवाबों:
मुझे लगता है कि लेन-देन सेवा की परत पर है। यह वह है जो काम की इकाइयों और उपयोग के मामलों के बारे में जानता है। यदि आपके पास कई डीएओ को एक सेवा में इंजेक्ट किया गया है जो एक ही लेनदेन में एक साथ काम करने की आवश्यकता है तो यह सही उत्तर है।
सामान्य तौर पर मैं दूसरों से यह कहते हुए सहमत होता हूं कि लेनदेन आमतौर पर सेवा स्तर पर शुरू किए जाते हैं (यह इस बात पर निर्भर करता है कि आपको किस प्रकार की आवश्यकता है)।
हालाँकि, इस बीच मैंने भी जोड़ना शुरू कर दिया @Transactional(propagation = Propagation.MANDATORY)
अपनी DAO परत (और अन्य परतों को की अनुमति नहीं दी है जो लेन-देन शुरू करने की अनुमति नहीं है, लेकिन मौजूदा वाले की आवश्यकता है) क्योंकि त्रुटियों का पता लगाना बहुत आसान है, जहाँ आप कॉलर में लेनदेन शुरू करना भूल गए हैं ( सेवा पसंद है)। यदि आपके डीएओ को अनिवार्य प्रचार के साथ एनोटेट किया जाता है, तो आपको यह कहते हुए अपवाद मिलेगा कि विधि लागू होने पर कोई सक्रिय लेनदेन नहीं होता है।
मेरे पास एक एकीकरण परीक्षण भी है जहां मैं इस एनोटेशन के लिए सभी बीन्स (बीन पोस्ट प्रोसेसर) की जांच करता हूं और विफल हो जाता है यदि @Transactional
बीन में अनिवार्य के अलावा प्रचार के साथ एक एनोटेशन होता है जो सेवाओं की परत से संबंधित नहीं है। इस तरह मैं सुनिश्चित करता हूं कि हम गलत लेयर पर लेनदेन शुरू न करें।
@Transactional
सेवा कार्यान्वयन वर्ग में रखना चाहिए, और मुझे @Transactional(propagation = MANDATORY)
DAO (रिपॉजिटरी) वर्ग के कार्यान्वयन पर रखना चाहिए ?
ट्रांसेक्शनल एनोटेशन को उन सभी परिचालनों के आसपास रखा जाना चाहिए जो अविभाज्य हैं।
उदाहरण के लिए, आपका कॉल "पासवर्ड बदलें" है। जिसमें दो ऑपरेशन होते हैं
तो उपरोक्त में, यदि ऑडिट विफल हो जाता है, तो क्या पासवर्ड परिवर्तन भी विफल हो जाना चाहिए? यदि ऐसा है, तो लेनदेन लगभग 1 और 2 होना चाहिए (इसलिए सेवा स्तर पर)। यदि ईमेल विफल हो जाता है (शायद इस पर किसी प्रकार की विफलता सुरक्षित होनी चाहिए, तो यह विफल नहीं होगी) तो क्या यह परिवर्तन पासवर्ड और ऑडिट को वापस करना चाहिए?
ये इस तरह के प्रश्न हैं जो आपको यह तय करने की आवश्यकता है कि यह कहां रखा जाए @Transactional
।
पारंपरिक स्प्रिंग आर्किटेक्चर के लिए सही उत्तर यह है कि दूसरों को पहले से ही वर्णित कारणों के लिए, सेवा वर्गों पर ट्रांजेक्शनल शब्दार्थों को रखना है।
स्प्रिंग में एक उभरती प्रवृत्ति डोमेन-संचालित डिज़ाइन (DDD) की ओर है। स्प्रिंग रूओ अच्छी तरह से प्रवृत्ति का उदाहरण देता है। विचार यह है कि डोमेन ऑब्जेक्ट POJOs को बहुत अधिक समृद्ध बनाने की तुलना में वे विशिष्ट स्प्रिंग आर्किटेक्चर (आमतौर पर वे एनीमिक ) हैं, और विशेष रूप से डोमेन ऑब्जेक्ट्स पर लेनदेन और दृढ़ता शब्दार्थ रखने के लिए। ऐसे मामलों में जहां सभी की आवश्यकता होती है सरल CRUD संचालन, वेब नियंत्रक सीधे डोमेन ऑब्जेक्ट POJOs पर काम करते हैं (वे इस संदर्भ में संस्थाओं के रूप में कार्य कर रहे हैं), और कोई सेवा स्तरीय नहीं है। ऐसे मामलों में जहां डोमेन ऑब्जेक्ट्स के बीच किसी प्रकार के समन्वय की आवश्यकता होती है, आपके पास एक सर्विस बीन हैंडल हो सकता है, जिसके साथ@Transaction
परंपरा के अनुसार। आप डोमेन ऑब्जेक्ट पर लेन-देन के प्रसार को कुछ इस तरह सेट कर सकते हैं REQUIRED
ताकि डोमेन ऑब्जेक्ट किसी भी मौजूदा लेनदेन का उपयोग करें, जैसे कि लेनदेन जो सेवा बीन पर शुरू किया गया था।
तकनीकी रूप से यह तकनीक AspectJ और का उपयोग करती है <context:spring-configured />
। Roo डोमेन ऑब्जेक्ट सामान (मूल रूप से फ़ील्ड्स और व्यावसायिक विधियों) से इकाई शब्दार्थ (लेनदेन और दृढ़ता) को अलग करने के लिए AspectJ इंटर-टाइप परिभाषाओं का उपयोग करता है।
सामान्य मामला सेवा स्तर के स्तर पर व्याख्या करना होगा, लेकिन यह वास्तव में आपकी आवश्यकताओं पर निर्भर करता है।
सेवा स्तर पर नोट करने से DAO स्तर पर एनोटेटिंग की तुलना में अधिक लेन-देन होगा। लेन-देन के अलगाव स्तर के आधार पर, जो समस्याओं को हल कर सकते हैं, जैसे कि समवर्ती लेनदेन जैसे एक-दूसरे के परिवर्तन को देखेंगे। दोहराए जाने वाले विवरण।
DAO पर एनोटेटिंग लेनदेन को यथासंभव कम रखेगा, इस कमी के साथ कि आपकी सेवा परत की कार्यक्षमता एक एकल (रोलबैक योग्य) लेनदेन में नहीं होगी।
अगर प्रचार मोड डिफ़ॉल्ट पर सेट है, तो दोनों परतों को एनोटेट करने का कोई मतलब नहीं है।
मैं परत @Transactional
पर @Service
रखता हूं और rollbackFor
किसी भी अपवाद को निर्धारित करता हूं औरreadOnly
लेनदेन को आगे बढ़ाता ।
डिफ़ॉल्ट रूप @Transactional
से केवल RuntimeException
(अनचेक Exception.class
किए गए अपवाद) की तलाश होगी, किसी भी अपवाद के लिए रोलबैक (चेक किए गए अपवाद) पर रोलबैक करके।
@Transactional(readOnly = false, rollbackFor = Exception.class)
चेक किए गए बनाम अनियोजित अपवाद देखें ।
या क्या यह दोनों "परतों" की व्याख्या करने के लिए समझ में आता है? - सेवा की परत और डाओ की परत दोनों को एनोटेट करने का कोई मतलब नहीं है - अगर कोई यह सुनिश्चित करना चाहता है कि DAO विधि को हमेशा प्रसार (DAO) में "अनिवार्य" के साथ एक सेवा परत से कहा जाता है। यह DAO विधियों के लिए UI परत (या नियंत्रकों) से बुलाए जाने के लिए कुछ प्रतिबंध प्रदान करेगा। इसके अलावा - जब यूनिट विशेष रूप से DAO परत का परीक्षण कर रही है - DAO एनोटेट होने से यह भी सुनिश्चित होगा कि यह लेनदेन संबंधी कार्यक्षमता के लिए परीक्षण किया गया है।
propagation=Propagation.REQUIRES_NEW
। अन्यथा ज्यादातर मामलों के लिए, जिनमें प्रचार = अनिवार्य शामिल है, DAO सिर्फ सेवा स्तर द्वारा शुरू किए गए मौजूदा लेनदेन में भाग लेगा।
इसके अलावा, स्प्रिंग केवल ठोस वर्गों पर एनोटेशन का उपयोग करने की सलाह देता है और इंटरफेस नहीं।
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
डेटाबेस स्तर में लेनदेन के लिए
ज्यादातर मैंने @Transactional
DAO का सिर्फ मेथड लेवल पर उपयोग किया है, इसलिए कॉन्फ़िगरेशन विशेष रूप से एक मेथड के लिए हो सकता है / डिफ़ॉल्ट (आवश्यक) का उपयोग कर
DAO की विधि जो डेटा प्राप्त करती है (चयन ..) - इसके
@Transactional
लिए लेन-देन इंटरसेप्टर / और AOP प्रॉक्सी के कारण कुछ ओवरहेड की आवश्यकता नहीं हो सकती है जिसे निष्पादित करने की आवश्यकता है।
DAO के तरीके जो इन्सर्ट / अपडेट करते हैं, मिलेंगे @Transactional
Transctional पर बहुत अच्छा ब्लॉग
आवेदन स्तर के लिए -
मैं व्यापार तर्क के लिए लेन-देन का उपयोग कर रहा हूं मैं अप्रत्याशित त्रुटि के मामले में रोलबैक करने में सक्षम होना चाहूंगा
@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){
try {
//service logic here
} catch(Throwable e) {
log.error(e)
throw new MyApplicationException(..);
}
}
Transactional
मेंJava
आमतौर पर, किसी को सेवा स्तर पर लेनदेन करना चाहिए।
लेकिन जैसा कि पहले कहा गया है, एक ऑपरेशन की परमाणुता वह है जो हमें बताती है कि एक एनोटेशन कहां आवश्यक है। इस प्रकार, यदि आप हाइबरनेट जैसे चौखटे का उपयोग करते हैं, जहां किसी ऑब्जेक्ट पर एक एकल "सेव / अपडेट / डिलीट / ... संशोधन" ऑपरेशन में कई तालिकाओं में कई पंक्तियों को संशोधित करने की क्षमता है (क्योंकि ऑब्जेक्ट ग्राफ के माध्यम से कैस्केड), बेशक इस विशिष्ट डीएओ पद्धति पर लेनदेन प्रबंधन भी होना चाहिए।
@Transactional
एनोटेशन को सभी ऑपरेशनों के आसपास रखा जाना चाहिए जो अविभाज्य हैं। @Transactional
लेन-देन के प्रसार का उपयोग करके स्वचालित रूप से नियंत्रित किया जाता है। इस मामले में यदि किसी अन्य विधि को वर्तमान विधि द्वारा बुलाया जाता है, तो उस पद्धति में चल रहे लेनदेन में शामिल होने का विकल्प होगा।
तो चलो उदाहरण लेते हैं:
हमारे पास 2 मॉडल हैं यानी Country
और City
। के संबंध में मैपिंग Country
और City
मॉडल एक जैसे Country
कई शहर हो सकते हैं, इसलिए मैपिंग की तरह है,
@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;
यहाँ देश ने उन्हें लाने के साथ कई शहरों की मैपिंग की Lazily
। इसलिए यहाँ पर भूमिका आती है @Transactinal
जब हम डेटाबेस से देश की वस्तु को पुनः प्राप्त करते हैं तो हमें देश के ऑब्जेक्ट का सारा डेटा मिल जाएगा लेकिन शहरों का सेट नहीं मिलेगा क्योंकि हम शहरों को ला रहे हैं LAZILY
।
//Without @Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//After getting Country Object connection between countryRepository and database is Closed
}
जब हम देश के ऑब्जेक्ट से शहरों के सेट का उपयोग करना चाहते हैं, तो हम उस सेट में शून्य मान प्राप्त करेंगे क्योंकि सेट का ऑब्जेक्ट केवल यह सेट सेट के मूल्यों को प्राप्त करने के लिए डेटा के साथ आरंभिक नहीं है, जिसका हम उपयोग करते हैं @Transactional
अर्थात
//with @Transactional
@Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
Object object = country.getCities().size();
}
तो मूल रूप @Transactional
से सेवा अंत बिंदु के साथ कनेक्शन बंद किए बिना एकल लेनदेन में कई कॉल कर सकते हैं।
@Transactional
वास्तव में क्या है का एक
@Transactional
सेवा स्तर पर इस्तेमाल किया जाना चाहिए के रूप में यह व्यापार तर्क होते हैं। DAO परत में आमतौर पर केवल डेटाबेस CRUD ऑपरेशन होते हैं।
// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
स्प्रिंग डॉक: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html
सेवा परत जोड़ने के लिए सबसे अच्छी जगह है @Transactional
एनोटेशन क्योंकि यहां मौजूद अधिकांश व्यावसायिक तर्क हैं, इसमें विस्तार स्तर का उपयोग-मामला व्यवहार होता है।
मान लीजिए कि हम इसे डीएओ से जोड़ते हैं और सेवा से हम 2 डीएओ कक्षाएं बुला रहे हैं, एक असफल और दूसरी सफलता, अगर इस मामले में @Transactional
सेवा पर नहीं है एक डीबी प्रतिबद्ध होगा और अन्य रोलबैक होगा।
इसलिए मेरी सिफारिश इस एनोटेशन का बुद्धिमानी से उपयोग करें और केवल सेवा स्तर पर उपयोग करें।
सबसे पहले आइए परिभाषित करें कि हमें लेनदेन का उपयोग कहां करना है ?
मुझे लगता है कि सही उत्तर है - जब हमें यह सुनिश्चित करने की आवश्यकता होती है कि क्रियाओं का क्रम एक परमाणु संचालन के रूप में एक साथ समाप्त हो जाएगा या कोई भी कार्रवाई विफल होने पर भी कोई बदलाव नहीं किया जाएगा।
व्यापार तर्क को सेवाओं में लगाने के लिए यह अच्छी तरह से जाना जाता है। इसलिए सेवा विधियों में अलग-अलग क्रियाएं हो सकती हैं जिन्हें कार्य की एकल तार्किक इकाई के रूप में निष्पादित किया जाना चाहिए। यदि ऐसा है - तो इस तरह के तरीके को ट्रांसेक्शनल के रूप में चिह्नित किया जाना चाहिए । बेशक, हर विधि को इस तरह की सीमा की आवश्यकता नहीं है, इसलिए आपको पूरी सेवा को लेन-देन के रूप में चिह्नित करने की आवश्यकता नहीं है ।
और इससे भी अधिक - इस बात पर ध्यान देना न भूलें कि @ स्पष्ट रूप से, विधि प्रदर्शन को कम कर सकता है। पूरी तस्वीर देखने के लिए आपको लेन-देन अलगाव स्तर जानना होगा। यह जानते हुए भी कि आप @Transactional के उपयोग से बचने में मदद कर सकते हैं जहाँ इसकी आवश्यकता नहीं है।
DAO और सर्विस लेयर के बीच एक अलग मध्य परत में @Transactional रखना बेहतर है । चूंकि, रोलबैक बहुत महत्वपूर्ण है, आप अपने सभी DB हेरफेर को मध्य परत में रख सकते हैं और सर्विस लेयर में व्यावसायिक तर्क लिख सकते हैं। मध्य परत आपके DAO परतों के साथ बातचीत करेगी।
यह ObjectOptimisticLockingFailureException जैसी कई स्थितियों में आपकी सहायता करेगा - यह अपवाद आपके लेन-देन के समाप्त होने के बाद ही होता है। इसलिए, आप इसे मध्य परत में नहीं पकड़ सकते हैं, लेकिन अब आप अपनी सेवा परत में पकड़ सकते हैं। यह संभव नहीं होगा यदि आपके पास सर्विस लेयर में @ ट्रेंसेक्शनल हो। यद्यपि आप नियंत्रक में पकड़ सकते हैं लेकिन नियंत्रक को यथासंभव स्वच्छ होना चाहिए।
यदि आप सभी सेव, डिलीट और अपडेट विकल्पों को पूरा करने के बाद अलग थ्रेड में मेल या एसएमएस भेज रहे हैं, तो आप इसे अपनी मध्य परत में लेन-देन पूरा होने के बाद सेवा में कर सकते हैं। दोबारा, यदि आप सेवा स्तर में @ सूचना का उल्लेख करते हैं, तो आप मेल करेंगे भले ही आपका लेनदेन विफल हो जाए।
तो एक मध्य @ ट्रान्सनेशन लेयर होने से आपके कोड को बेहतर और आसान बनाने में मदद मिलेगी। अन्यथा, यदि आप DAO परत में उपयोग करते हैं, तो आप सभी कार्यों को रोलबैक करने में सक्षम नहीं हो सकते हैं। यदि आप सर्विस लेयर में उपयोग करते हैं, तो आपको कुछ मामलों में AOP (Aspect Oriented Programming) का उपयोग करना पड़ सकता है ।
आदर्श रूप से, सेवा परत (प्रबंधक) आपके व्यवसाय तर्क का प्रतिनिधित्व करता है और इसलिए इसे एनोटेट किया जाना चाहिए। सेवा की @Transactional
परत DB ऑपरेशन करने के लिए अलग-अलग DAO कह सकती है। एक ऐसी स्थिति मानें जहां आपके पास सेवा पद्धति में डीएओ संचालन की संख्या एन है। यदि आपका पहला DAO ऑपरेशन विफल हो गया, तो अन्य अभी भी पारित हो सकते हैं और आप असंगत DB अवस्था को समाप्त कर देंगे। एनोटेटिंग सेवा की परत आपको ऐसी स्थितियों से बचा सकती है।
मैं @Transactional
विधि स्तर पर सेवाओं की परत पर उपयोग करना पसंद करता हूं ।