स्प्रिंग डेटा के MongoTemplate और MongoRepository के बीच क्या अंतर है?


96

मुझे एक एप्लिकेशन लिखने की आवश्यकता है जिसके साथ मैं वसंत-डेटा और मोंगोडब का उपयोग करके जटिल प्रश्न कर सकता हूं। मैं MongoRepository का उपयोग करके शुरू कर रहा हूं लेकिन उदाहरण खोजने या वास्तव में सिंटैक्स को समझने के लिए जटिल प्रश्नों से जूझ रहा हूं।

मैं इस तरह के प्रश्नों के बारे में बात कर रहा हूँ:

@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
    List<User> findByEmailOrLastName(String email, String lastName);
}

या JSON आधारित प्रश्नों का उपयोग जो मैंने परीक्षण और त्रुटि के कारण किया क्योंकि मुझे वाक्यविन्यास अधिकार नहीं मिलता है। मोंगोडब प्रलेखन (गलत सिंटैक्स के कारण गैर-कार्यशील उदाहरण) पढ़ने के बाद भी।

@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
    @Query("'$or':[{'firstName':{'$regex':?0,'$options':'i'}},{'lastName':{'$regex':?0,'$options':'i'}}]")
    List<User> findByEmailOrFirstnameOrLastnameLike(String searchText);
} 

सभी प्रलेखन के माध्यम से पढ़ने के बाद ऐसा लगता है कि mongoTemplateकहीं बेहतर दस्तावेज है MongoRepository। मैं निम्नलिखित प्रलेखन की बात कर रहा हूँ:

http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/

क्या आप मुझे बता सकते हैं कि उपयोग करने के लिए अधिक सुविधाजनक और शक्तिशाली क्या है? mongoTemplateया MongoRepository? क्या दोनों एक ही परिपक्व हैं या उनमें से एक में अधिक विशेषताओं का अभाव है तो दूसरे में?

जवाबों:


130

"सुविधाजनक" और "उपयोग करने के लिए शक्तिशाली" कुछ हद तक लक्ष्यों के विपरीत हैं। रिपॉजिटरी टेम्प्लेट की तुलना में कहीं अधिक सुविधाजनक हैं, लेकिन निश्चित रूप से उत्तरार्द्ध आपको निष्पादित करने के बारे में अधिक बारीक नियंत्रण प्रदान करते हैं।

चूंकि रिपॉजिटरी प्रोग्रामिंग मॉडल कई स्प्रिंग डेटा मॉड्यूल के लिए उपलब्ध है, इसलिए आपको स्प्रिंग डेटा MongoDB संदर्भ डॉक्स के सामान्य अनुभाग में इसके लिए अधिक गहराई से प्रलेखन मिलेगा ।

टी एल; डॉ

हम आम तौर पर निम्नलिखित दृष्टिकोण की सलाह देते हैं:

  1. रिपॉजिटरी एब्सट्रैक्ट से शुरू करें और क्वेरी व्युत्पत्ति तंत्र या मैन्युअल रूप से परिभाषित प्रश्नों का उपयोग करके सरल प्रश्नों की घोषणा करें।
  2. अधिक जटिल प्रश्नों के लिए, रिपॉजिटरी में मैन्युअल रूप से लागू किए गए तरीकों को जोड़ें (जैसा कि यहां दस्तावेज किया गया है)। कार्यान्वयन के उपयोग के लिए MongoTemplate

विवरण

आपके उदाहरण के लिए यह कुछ इस तरह दिखेगा:

  1. अपने कस्टम कोड के लिए एक इंटरफ़ेस परिभाषित करें:

    interface CustomUserRepository {
    
      List<User> yourCustomMethod();
    }
  2. इस वर्ग के लिए एक कार्यान्वयन जोड़ें और यह सुनिश्चित करने के लिए कि हम कक्षा पा सकते हैं, नामकरण सम्मेलन का पालन करें।

    class UserRepositoryImpl implements CustomUserRepository {
    
      private final MongoOperations operations;
    
      @Autowired
      public UserRepositoryImpl(MongoOperations operations) {
    
        Assert.notNull(operations, "MongoOperations must not be null!");
        this.operations = operations;
      }
    
      public List<User> yourCustomMethod() {
        // custom implementation here
      }
    }
  3. अब अपने बेस रिपॉजिटरी इंटरफेस को कस्टम को बढ़ाएं और इन्फ्रास्ट्रक्चर स्वतः ही आपके कस्टम कार्यान्वयन का उपयोग करेगा:

    interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository {
    
    }

इस तरह आपको अनिवार्य रूप से विकल्प मिलता है: जो कुछ भी घोषित करना आसान है UserRepository, वह सब कुछ जो बेहतर तरीके से लागू होता है, मैन्युअल रूप से हो जाता है CustomUserRepository। अनुकूलन विकल्प यहां प्रलेखित हैं


हाय ओलिवर, यह वास्तव में काम नहीं करता है। स्प्रिंग-डेटा कस्टम नाम से बाहर एक क्वेरी को स्वतः उत्पन्न करने की कोशिश करता है। yourCustomMethod ()। यह कहेगा कि "आपका" डोमेन वर्ग में एक मान्य क्षेत्र नहीं है। मैंने मैनुअल का पालन किया और यह भी जांचा कि आप इसे स्प्रिंग-डेटा-जपा-उदाहरण कैसे कर रहे हैं। कोई भाग्य नहीं। स्प्रिंग-डेटा हमेशा कस्टम-इंटरफ़ेस को रिपॉजिटरी क्लास तक बढ़ाते हुए ऑटो-जेनरेट करने की कोशिश करता है। एकमात्र अंतर यह है कि मैं MongoRepository का उपयोग कर रहा हूं और CrudRepository का नहीं क्योंकि मैं अब तक Iterators के साथ काम नहीं करना चाहता। यदि आप एक संकेत है यह सराहना की जाएगी।
क्रिस्टोफर आर्मस्ट्रांग

10
कार्यान्वयन वर्ग को गलत करने के लिए सबसे आम गलती है: यदि आपका आधार रेपो इंटरफ़ेस कहा जाता है YourRepository, तो कार्यान्वयन वर्ग को नाम देना होगा YourRepositoryImpl। क्या यह मामला है? यदि ऐसा है तो मैं GitHub या इस तरह के एक नमूना परियोजना पर एक नज़र लेने के लिए खुश हूँ ...
ओलिवर ड्रोट्बोहम

5
हाय ओलिवर, Impl वर्ग का नाम गलत था जैसा कि आपने मान लिया है। मैंने नाम को समायोजित कर लिया है और यह अभी काम कर रहा है। आपकी प्रतिक्रिया के लिए बहुत बहुत धन्यवाद। इस तरह से क्वेरी विकल्पों के विभिन्न प्रकारों का उपयोग करने में सक्षम होने के लिए वास्तव में अच्छा है। के माध्यम से अच्छी तरह से सोचा!
क्रिस्टोफर आर्मस्ट्रांग

यह उत्तर इतना स्पष्ट नहीं है। इस उदाहरण द्वारा सब कुछ करने के बाद मैं इस मुद्दे पर आता हूं: stackoverflow.com/a/13947263/449553 । इस उदाहरण से ऐसा लग रहा है कि नामकरण सम्मेलन अधिक सख्त है।
मिसेज़ेल

1
# 2 पर कार्यान्वयन वर्ग को गलत नाम दिया गया है: होना चाहिए CustomUserRepositoryऔर नहीं CustomerUserRepository
Cotta

28

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

इसके बजाय, MongoTemplateमार्ग के साथ जाएं और अपनी स्वयं की डेटा एक्सेस परत बनाएं जो आपको स्प्रिंग प्रोग्रामर द्वारा सामना किए गए कॉन्फ़िगरेशन बुरे सपने से मुक्त करता है। MongoTemplateवास्तव में इंजीनियरों के लिए उद्धारकर्ता है जो अपने स्वयं के वर्गों और अंतःक्रियाओं को बनाने में सहज हैं क्योंकि इसमें बहुत लचीलापन है। संरचना कुछ इस तरह हो सकती है:

  1. एक MongoClientFactoryक्लास बनाएं जो एप्लिकेशन स्तर पर चलेगा और आपको एक MongoClientऑब्जेक्ट देगा। आप इसे सिंगलटन के रूप में लागू कर सकते हैं या एनम सिंगलटन का उपयोग कर सकते हैं (यह धागा सुरक्षित है)
  2. एक डेटा एक्सेस बेस क्लास बनाएं जिससे आप प्रत्येक डोमेन ऑब्जेक्ट के लिए डेटा एक्सेस ऑब्जेक्ट विरासत में प्राप्त कर सकते हैं)। बेस क्लास एक MongoTemplate ऑब्जेक्ट बनाने के लिए एक विधि को लागू कर सकता है जिसे आप क्लास विशिष्ट तरीके सभी DB एक्सेस के लिए उपयोग कर सकते हैं
  3. प्रत्येक डोमेन ऑब्जेक्ट के लिए प्रत्येक डेटा एक्सेस क्लास बुनियादी तरीकों को लागू कर सकता है या आप उन्हें बेस क्लास में लागू कर सकते हैं
  4. नियंत्रक विधियाँ आवश्यकतानुसार डेटा एक्सेस कक्षाओं में विधियों को कॉल कर सकती हैं।

हाय @rameshpa क्या मैं MongoTemplate और रिपोजिटरी दोनों को एक ही प्रोजेक्ट में उपयोग कर सकता हूं? .. क्या इसका उपयोग संभव है
गौरांग

1
आप जिस MongoTemplate को लागू करते हैं, वह रिपॉजिटरी द्वारा उपयोग किए गए कनेक्शन की तुलना में DB के लिए एक अलग कनेक्शन होगा। परमाणुता एक मुद्दा हो सकता है। इसके अलावा, मैं एक धागे पर दो अलग-अलग कनेक्शनों का उपयोग करने की अनुशंसा नहीं करूंगा यदि आपको अनुक्रमण की आवश्यकता है
rameshpa

23

FWIW, बहु-थ्रेडेड वातावरण में अपडेट के बारे में:

  • MongoTemplateप्रदान करता है "परमाणु" आउट-ऑफ-द-बॉक्स संचालन updateFirst , updateMulti, findAndModify,upsert ... जो आप एक ही आपरेशन में एक दस्तावेज़ संशोधित करने की अनुमति। Updateइन विधियों द्वारा उपयोग की जाने वाली वस्तु भी आपको केवल संबंधित क्षेत्रों को लक्षित करने की अनुमति देती है
  • MongoRepositoryकेवल आप देता है बुनियादी CRUD संचालन find , insert, save, delete, जो युक्त POJOs साथ काम सभी क्षेत्रों । यह आपको या तो दस्तावेजों को कई चरणों में अद्यतन करने के लिए मजबूर करता है (1. findअद्यतन करने के लिए दस्तावेज़, 2. लौटे हुए पीओजेओ से संबंधित क्षेत्रों को संशोधित करें, और फिर 3. saveयह), या हाथ से अपने स्वयं के अपडेट प्रश्नों को परिभाषित करें @Query

एक बहु-थ्रेडेड वातावरण में, जैसे कि एक जावा बैक-एंड कई REST एंडपॉइंट्स के साथ, एकल-विधि अद्यतन एक दूसरे के परिवर्तनों को अधिलेखित करने के लिए दो समवर्ती अद्यतनों की संभावना को कम करने के लिए जाने का तरीका है।

उदाहरण: इस तरह एक दस्तावेज दिया: { _id: "ID1", field1: "a string", field2: 10.0 }और दो अलग-अलग सूत्र समवर्ती इसे अद्यतन कर रहे हैं ...

इसके साथ MongoTemplateकुछ इस तरह दिखेगा:

THREAD_001                                                      THREAD_002
|                                                               |
|update(query("ID1"), Update().set("field1", "another string")) |update(query("ID1"), Update().inc("field2", 5))
|                                                               |
|                                                               |

और दस्तावेज़ के लिए अंतिम स्थिति हमेशा होती है { _id: "ID1", field1: "another string", field2: 15.0 } क्योंकि प्रत्येक थ्रेड केवल एक बार डीबी का आरोप लगा रहा है और केवल निर्दिष्ट फ़ील्ड को बदल दिया गया है।

जबकि एक ही मामला परिदृश्य के साथ MongoRepository इस तरह दिखेगा:

THREAD_001                                                      THREAD_002
|                                                               |
|pojo = findById("ID1")                                         |pojo = findById("ID1")
|pojo.setField1("another string") /* field2 still 10.0 */       |pojo.setField2(pojo.getField2()+5) /* field1 still "a string" */
|save(pojo)                                                     |save(pojo)
|                                                               |
|                                                               |

और अंतिम दस्तावेज { _id: "ID1", field1: "another string", field2: 10.0 }या तो ऑपरेशन { _id: "ID1", field1: "a string", field2: 15.0 }पर निर्भर करता है, जो saveपिछले डीबी को हिट करता है।
(नोट: भले ही हमने स्प्रिंग डेटा एनोटेशन का उपयोग किया हो@Version में सुझाए गए अनुसार करते हैं, तो भी बहुत कुछ नहीं बदलेगा: saveसंचालन में से एक एक फेंक देगा OptimisticLockingFailureException, और अंतिम दस्तावेज़ अभी भी उपरोक्त में से एक होगा, जिसमें दोनों के बजाय केवल एक फ़ील्ड अपडेट किया जाएगा। )

तो मैं कहूंगा कि MongoTemplateयह एक बेहतर विकल्प है , जब तक कि आपके पास बहुत विस्तृत POJO मॉडल न हो या MongoRepositoryकिसी कारण से कस्टम क्वेरी क्षमताओं की आवश्यकता हो ।


अच्छे अंक / उदाहरण। हालाँकि आपके दौड़ की स्थिति का उदाहरण और अवांछित परिणाम उस बहुत परिदृश्य को रोकने के लिए @Version का उपयोग करके बचा जा सकता है।
Madbreaks

@Madbreaks क्या आप इसे प्राप्त करने के बारे में कोई संसाधन प्रदान कर सकते हैं? किसी भी आधिकारिक डॉक्टर शायद?
कार्तिकेयन

@Version एनोटेशन के बारे में स्प्रिंग डेटा डॉक्स: docs.spring.io/spring-data/mongodb/docs/current/reference/html/…
करीम तौफीक

1
@Madbreaks कि बाहर इशारा करने के लिए धन्यवाद। हां, @Versionदूसरे थ्रेड को पहले से सहेजे गए डेटा को ओवरराइट करने से "बचें" - इस अर्थ में "से बचें" कि यह अपडेट को छोड़ देगा और OptimisticLockingFailureExceptionइसके बजाय फेंक देगा । यदि आप चाहते हैं कि अपडेट सफल रहे तो आपको एक रीट्री मैकेनिज्म लागू करना होगा। MongoTemplate आपको पूरे परिदृश्य से बचने की अनुमति देता है।
Walen
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.