2015-06-17 4 views
8

मेरे पास स्प्रिंग डेटा जेपीए का उपयोग कर स्प्रिंग बूट 1.3.एम 1 वेब एप्लिकेशन है। आशावादी लॉकिंग के लिए, मैं निम्नलिखित कर रहा हूं:ऑप्टिस्टिक लॉकिंग मैन्युअल रूप से संस्करण फ़ील्ड सेट करते समय अपवाद फेंक नहीं

  1. इकाई में संस्करण कॉलम एनोटेट करें: @Version private long version;। मैंने डेटाबेस तालिका को देखकर पुष्टि की, कि यह क्षेत्र ठीक से बढ़ रहा है।
  2. जब कोई उपयोगकर्ता संपादन के लिए इकाई का अनुरोध करता है, तो version फ़ील्ड भी भेजता है।
  3. जब उपयोगकर्ता संपादन के बाद सबमिट करता है, version फ़ील्ड को एक छिपे हुए फ़ील्ड या किसी चीज़ के रूप में प्राप्त करना।
  4. सर्वर पक्ष, इकाई की ताजा प्रति प्राप्त करना, और फिर version फ़ील्ड के साथ वांछित फ़ील्ड को अपडेट करना। इस तरह:

    User user = userRepository.findOne(id); 
    user.setName(updatedUser.getName()); 
    user.setVersion(updatedUser.getVersion()); 
    userRepository.save(user); 
    

मैं जब संस्करणों से मेल नहीं होता इस अपवाद फेंकने के लिए उम्मीद कर रहा था। लेकिन ऐसा नहीं है। गुगलिंग, मुझे कुछ पोस्ट मिलीं कि हम संलग्न इकाई की @Vesion संपत्ति सेट नहीं कर सकते हैं, जैसे कि मैं उपरोक्त तीसरे कथन में कर रहा हूं।

तो, मुझे लगता है कि मुझे मैन्युअल रूप से संस्करण मिलान के लिए जांच करनी होगी और अपवाद को फेंकना होगा। क्या यह सही तरीका होगा, या मुझे कुछ याद आ रहा है?

+0

हाइबरनेट * * आप @version क्षेत्र मैन्युअल रूप से संशोधित (विपरीत, कहते हैं, OpenJPA) जाने है, लेकिन इस जेपीए विनिर्देश के साथ लाइन में नहीं है (देखें अनुभाग 11.1.54 http: // stackoverflow.com/questions/30098350/optimisticlockexception-not-thrown-when-version-has-changed-in-spring-boot-proje/30101542#30101542)। यदि आप इकाई को सीधे बाध्यकारी थे तो आपका दृष्टिकोण काम करना चाहिए। क्या आप अपनी सेवा में डीटीओ पास कर रहे हैं और यहां इकाई को पॉप्युलेट कर रहे हैं? –

+0

हां, ऊपर दिए गए मेरे कोड में अद्यतन यूज़र डीटीओ है। – Sanjay

उत्तर

11

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

उदा।

यह

Foo foo = fooRepo.findOne(id); // assume version is 2 here 
foo.setSomeField(....); 

// Assume at this point of time someone else change the record in DB, 
// and incrementing version in DB to 3 

fooRepo.flush(); // forcing an update, then Optimistic Concurrency exception will be thrown 

हालांकि इस काम नहीं करेगा

Foo foo = fooRepo.findOne(id); // assume version is 2 here 
foo.setSomeField(....); 
foo.setVersion(1); 
fooRepo.flush(); // forcing an update, no optimistic concurrency exception 
        // Coz Hibernate is "smart" enough to use the original 2 for comparison 

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

class User { 
    private int version = 0; 
    //..... 

    public void setVersion(int version) { 
     if (this.version != version) { 
      throw new YourOwnOptimisticConcurrencyException(); 
     } 
    } 

    //..... 
} 
0

@AdrianShum जवाब का एक हिस्सा सही है: एक और तरीका है setVersion() में तर्क डाल करने के लिए जो, बजाय वास्तव में संस्करण स्थापित करने की है, यह संस्करण की जाँच करते हैं।

संस्करण की तुलना व्यवहार इस प्रकार मूल रूप से इस कदम:

  1. उसकी संस्करण संख्या के साथ संस्करणीकृत इकाई को पुनः प्राप्त, V1 कहा जाता है की सुविधा देता है।
  2. मान लीजिए कि आप कुछ इकाई की संपत्ति को संशोधित करते हैं, तो हाइबरनेट संस्करण संख्या को स्मृति में V2 में "स्मृति में बढ़ाता है"। यह डेटाबेस को छूता नहीं है।
  3. आप परिवर्तन करते हैं या वे स्वचालित रूप से पर्यावरण द्वारा प्रतिबद्ध होते हैं, फिर हाइबरनेट V2 मान के साथ इसके संस्करण संख्या सहित इकाई को अपडेट करने का प्रयास करेगा। हाइबरनेट द्वारा उत्पन्न अद्यतन क्वेरी केवल इकाई की रजिस्ट्री को संशोधित करेगी यदि यह आईडी और पिछले संस्करण संख्या (V1) से मेल खाती है।
  4. इकाई रजिस्ट्री सफलतापूर्वक संशोधित होने के बाद, इकाई V2 को इसके वास्तविक संस्करण मान के रूप में लेती है।

अब मान लीजिए कि चरण 1 और 3 के बीच इकाई को दूसरे लेनदेन द्वारा संशोधित किया गया था, इसलिए चरण 3 पर इसका संस्करण संख्या V1 नहीं है। फिर जब संस्करण संख्या भिन्न होती है तो अद्यतन क्वेरी किसी भी रजिस्ट्री को संशोधित नहीं करेगी, हाइबरनेट को एहसास हो जाएगा और अपवाद फेंक देगा।

आप बस इस व्यवहार का परीक्षण और जाँच लें कि अपवाद चरण 1 और 3.

संपादित के बीच अपने डेटाबेस पर सीधे संस्करण संख्या में फेरबदल फेंक दिया जाता है कर सकते हैं। जो जेपीए हठ प्रदाता पता नहीं आप स्प्रिंग डाटा जेपीए के साथ लेकिन जेपीए + हाइबरनेट साथ आशावादी ताला बारे में अधिक जानकारी मैं सुझाव है कि आप अध्याय 10 को पढ़ने के लिए उपयोग कर रहे हैं, खंड समवर्ती पहुँच को नियंत्रित करना, पुस्तक जावा हठ के साथ की हाइबरनेट (एक्शन में हाइबरनेट)

+2

आप जो भी चर्चा कर रहे हैं उससे चूक गए। हम सभी स्पष्ट हैं कि आशावादी समरूपता कैसे काम करती है। हम ध्यान केंद्रित कर रहे हैं, हाइबरनेट द्वारा बनाई गई अद्यतन क्वेरी के लिए, यह इकाई में '@ संस्करण' फ़ील्ड का उपयोग नहीं कर रहा है। इसके बजाए, हाइबरनेट कहीं और इकाई का संस्करण संग्रहीत कर रहा है और आशावादी समवर्ती जांच के लिए इसका उपयोग करता है। –

0

@ एड्रियन शम उत्तर के अलावा, मैं यह दिखाना चाहता हूं कि मैंने इस समस्या को कैसे हल किया। यदि आप मैन्युअल रूप से एंटिटी का संस्करण बदलना चाहते हैं और OptimisticConcurrencyException का कारण बनने के लिए एक अद्यतन करना चाहते हैं तो आप केवल अपने सभी फ़ील्ड के साथ एंटिटी कॉपी कर सकते हैं, इस प्रकार एक इकाई को अपना संदर्भ छोड़ने का कारण बनता है (EntityManager.detach() के समान)। इस तरह, यह एक उचित तरीके से व्यवहार करता है।

Entity entityCopy = new Entity(); 
entityCopy.setId(id); 
... //copy fields 
entityCopy.setVersion(0L); //set invalid version 
repository.saveAndFlush(entityCopy); //boom! OptimisticConcurrencyException 

संपादित करें: इकट्ठे संस्करण काम करता है, सिर्फ तभी जब हाइबरनेट कैश एक ही आईडी वाले इकाई शामिल नहीं है। यह काम नहीं करेगा:

Entity entityCopy = new Entity(); 
entityCopy.setId(repository.findOne(id).getId()); //instance loaded and cached 
... //copy fields 
entityCopy.setVersion(0L); //will be ignored due to cache 
repository.saveAndFlush(entityCopy); //no exception thrown 
+0

आप एक पूर्व-मौजूदा इकाई को कैसे देखते हैं लेकिन कैश में इसे पहले कोड उदाहरण बनाने के लिए नहीं है? – pgreen2

+0

@ pgreen2 इस परिदृश्य में आप मौजूदा इकाई को देखते हैं, लेकिन डीबी में बने रहने के लिए आप इसे उपयोगकर्ता द्वारा भेजे गए एक का उपयोग करके इकट्ठा करते हैं। अलग इकाई का संस्करण फ़ील्ड तब संशोधित है। इसके विपरीत, प्राप्त इकाई का संस्करण फ़ील्ड संशोधित नहीं है। – Dmitry

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