2012-11-27 15 views
17

मैंने जेपीए और लॉकिंग मोड के बारे में ओरेकल here के ब्लॉग पर एक लेख पढ़ा।जेपीए और आशावादी लॉकिंग मोड

मुझे OPTIMISTIC और OPTIMISTIC_FORCE_INCREMENT लॉक मोड प्रकारों के बीच अंतर को अच्छी तरह से समझ में नहीं आता है।

OPTIMISTIC मोड:

enter image description here

एक उपयोगकर्ता इस विधा के साथ एक इकाई ताले करते हैं, तो एक चेक और लेन-देन की शुरुआत में संस्करण क्षेत्र इकाई (@version) पर किया जाता है संस्करण पर एक जाँच लेनदेन के अंत में क्षेत्र भी किया जाता है। यदि संस्करण differents हैं, लेनदेन वापस रोल।

OPTIMISTIC_FORCE_INCREMENT मोड:

enter image description here

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

यह स्पष्ट प्रतीत होता है लेकिन मुझे OPTIMISTIC या OPTIMISTIC_FORCE_INCREMENT मोड का उपयोग कब करना चाहिए? एकमात्र मानदंड जो मैं देखता हूं वह OPTIMISTIC_FORCE_INCREMENT मोड लागू करना है जब मैं लेनदेन को दूसरों पर प्राथमिकता देना चाहता हूं क्योंकि यह मोड अन्य सभी लेनदेन चलाने वाले सभी को वापस ले जाएगा (यदि मैं अच्छी तरह से मैकेनिज्म समझता हूं)।

क्या OPTIMISTIC मोड के बजाय इस मोड को चुनने के लिए कोई और कारण है?

धन्यवाद

+0

मुझे लगता है कि हम उस इकाई को अद्यतन करने के मामले में OPTIMISTIC_FORCE_INCREMENT का उपयोग करते हैं जिसमें फ़ील्ड के रूप में अन्य प्रकार की इकाइयां होती हैं (@oneToOne, @oneToMany)। इसलिए हम OPTIMISTIC_FORCE_INCREMENT के साथ लॉक करते हैं उदाहरण के लिए सभी ListItem जब हम सूची अपडेट करना चाहते हैं। इस प्रकार, जब हम यह सुनिश्चित करते हैं कि हम उस इकाई से जुड़े सभी संस्थाओं को अपरिवर्तित कर रहे हैं। यही है ना ? –

उत्तर

10

आम तौर पर आप आशावादी लॉकिंग के लिए ताला() एपीआई का उपयोग कभी नहीं होगा। जेपीए स्वचालित रूप से किसी भी अद्यतन या हटाए जाने पर किसी भी संस्करण कॉलम की जांच करेगा।

आशावादी लॉकिंग के लिए लॉक() एपीआई का एकमात्र उद्देश्य तब होता है जब आपका अपडेट किसी अन्य ऑब्जेक्ट पर निर्भर करता है जो बदला/अपडेट नहीं होता है। यदि अन्य ऑब्जेक्ट बदलता है तो यह आपके लेनदेन को अभी भी असफल होने की अनुमति देता है।

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

आशावादी लॉकिंग हमेशा प्रतिबद्धता पर सत्यापित होती है, और प्रतिबद्ध होने तक सफलता की कोई गारंटी नहीं होती है। आप समय से पहले डेटाबेस ताले को मजबूर करने के लिए फ्लश() का उपयोग कर सकते हैं, या पहले की त्रुटि को ट्रिगर कर सकते हैं।

+0

कोई नहीं (डिफ़ॉल्ट मोड मुझे लगता है) और ऑप्टिमाइस्टिक के बीच क्या अंतर है? Thx –

+0

क्या फ्लश() इस प्रतिबद्धता से पहले संस्करण को बढ़ाने की गारंटी देता है कि यह अन्य लेन-देन के लिए दृश्यमान है? – Catweazle

38

इस लंबे उत्तर से डरो मत। यह विषय सरल नहीं है।

डिफ़ॉल्ट जेपीए तक लागू पढ़ें अगर आप किसी भी ताला (LockModeType.NONE का उपयोग कर के रूप में ही व्यवहार) का उल्लेख नहीं करते अलगाव स्तर प्रतिबद्ध है।

पढ़ें प्रतिबद्धगैर अस्तित्व की आवश्यकता है गंदा की पढ़ घटना। टी 2 के बाद बस टी 1 केवल टी 2 द्वारा किए गए परिवर्तन देख सकता है।

जेपीए में आशावादी लॉकिंग का उपयोग अलगाव स्तर रीसेट करने योग्य पढ़ता है।

यदि टी 1 शुरुआत में और लेनदेन के अंत में कुछ डेटा पढ़ता है, दोहराया जाने योग्य पढ़ता है कि टी 1 उसी डेटा को देखता है भले ही टी 2 ने डेटा बदल दिया हो और टी 1 के बीच में किया गया हो।

और यहां मुश्किल हिस्सा आता है। जेपीए प्राप्त करता है रीसेट करने योग्य को सबसे आसान तरीके से पढ़ता है: को रोकना गैर-दोबारा पढ़ने योग्य घटना। जेपीए आपके पढ़ने के स्नैपशॉट्स को रखने के लिए पर्याप्त परिष्कृत नहीं है। यह केवल अपवाद को बढ़ाकर दूसरे पढ़ने को रोकता है (यदि डेटा पहले पढ़ने से बदल गया है)।

आप दो आशावादी लॉक विकल्पों में से चुन सकते हैं: (जेपीए 1.0 में LockModeType.WRITE)

  • LockModeType.OPTIMISTIC (LockModeType.READ जेपीए 1.0 में)

  • LockModeType.OPTIMISTIC_FORCE_INCREMENT

अंतर क्या है दोनों के बिच में?

मुझे इस Person इकाई पर उदाहरणों के साथ उदाहरण दें।

@Entity 
public class Person { 
    @Id int id; 
    @Version int version; 
    String name; 
    String label; 
    @OneToMany(mappedBy = "person", fetch = FetchType.EAGER) 
    List<Car> cars; 
    // getters & setters 
} 

अब हम एक व्यक्ति का नाम दिया है जॉन डेटाबेस में संग्रहीत मान लें। हम इस व्यक्ति को टी 1 में पढ़ते हैं लेकिन दूसरे लेनदेन टी 2 में अपना नाम माइक पर बदलते हैं।

किसी भी ताला लगा

Person person1 = em1.find(Person.class, id, LockModeType.NONE); //T1 reads Person("John") 

Person person2 = em2.find(Person.class, id); //T2 reads Person("John") 
person2.setName("Mike"); //Changing name to "Mike" within T2 
em2.getTransaction().commit(); // T2 commits 

System.out.println(em1.find(Person.class, id).getName()); // prints "John" - entity is already in Persistence cache 
System.out.println(
    em1.createQuery("SELECT count(p) From Person p where p.name='John'") 
    .getSingleResult()); // prints 0 - ups! don't know about any John (Non-repetable read) 

आशावादी पढ़ने ताला बिना जब परिवर्तन अन्य संस्था (शायद एक गैर स्वामित्व संबंध) के लिए किया जाता

Person person1 = em1.find(Person.class, id, LockModeType.OPTIMISTIC); //T1 reads Person("John") 

    Person person2 = em2.find(Person.class, id); //T2 reads Person("John") 
    person2.setName("Mike"); //Changing name to "Mike" within T2 
    em2.getTransaction().commit(); // T2 commits 

    System.out.println(
      em1.createQuery("SELECT count(p) From Person p where p.name='John'") 
        .getSingleResult()); // OptimisticLockException - The object [[email protected]] cannot be updated because it has changed or been deleted since it was last read. 


LockModeType.OPTIMISTIC_FORCE_INCREMENT प्रयोग किया जाता है और हम अखंडता को संरक्षित करना चाहते हैं। मुझे जॉन के साथ एक नई कार प्राप्त करने का उदाहरण दें।

आशावादी पढ़ने ताला

Person john1 = em1.find(Person.class, id); //T1 reads Person("John") 

Person john2 = em2.find(Person.class, id, LockModeType.OPTIMISTIC); //T2 reads Person("John") 
//John gets a mercedes 
Car mercedes = new Car(); 
mercedes.setPerson(john2); 
em2.persist(mercedes); 
john2.getCars().add(mercedes); 
em2.getTransaction().commit(); // T2 commits 

//T1 doesn't know about John's new car. john1 in stale state. We'll end up with wrong info about John. 
if (john1.getCars().size() > 0) { 
    john1.setLabel("John has a car"); 
} else { 
    john1.setLabel("John doesn't have a car"); 
} 
em1.flush(); 

आशावादी लिखने ताला

Person john1 = em1.find(Person.class, id); //T1 reads Person("John") 
Person john2 = em2.find(Person.class, id, LockModeType.OPTIMISTIC_FORCE_INCREMENT); //T2 reads Person("John") 
//John gets a mercedes 
Car mercedes = new Car(); 
mercedes.setPerson(john2); 
em2.persist(mercedes); 
john2.getCars().add(mercedes); 
em2.getTransaction().commit(); // T2 commits 

//T1 doesn't know about John's new car. john1 in stale state. That's ok though because proper locking won't let us save wrong information about John. 
if (john1.getCars().size() > 0) { 
    john1.setLabel("John has a car"); 
} else { 
    john1.setLabel("John doesn't have a car"); 
} 
em1.flush(); // OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) 

हालांकि जेपीए कल्पना में एक निम्न टिप्पणी नहीं है, हाइबरनेट और EclipseLink अच्छी तरह से बर्ताव करता है और उसका उपयोग नहीं करते ।

संस्करणीकृत वस्तुओं के लिए, यह एक कार्यान्वयन LockMode- Type.OPTIMISTIC_FORCE_INCREMENT जहां LockModeType.OPTIMISTIC अनुरोध किया गया था, लेकिन इसके विपरीत नहीं का उपयोग करने के लिए स्वीकार्य है।

+0

मुझे लगता है कि जब आप em1.flush() करते हैं तो आपके अंतिम उदाहरण में कोई लॉक नहीं होता है, हमें अपवाद नहीं होना चाहिए था। हकीकत में क्योंकि आपने अपनी इकाइयों में संस्करण का उपयोग किया है: http://stackoverflow.com/a/19872657/1059372 – Eugene

+0

मैंने हाइबरनेट 4.3.6 के खिलाफ अपने उदाहरणों का परीक्षण किया। फाइनल और एक्लेप्सेलिंक 2.5.1। आपकी चिंता के बारे में: टिप्पणियों में हाइबरनेट संदेश दिखाई देता है। Eclipselink प्रिंट्स * OptimisticLockException ऑब्जेक्ट [व्यक्ति @ 716d7daf] को अपडेट नहीं किया जा सकता है क्योंकि यह आखिरी बार पढ़ने के बाद बदल गया है या हटा दिया गया है। * 'व्यक्ति' वास्तव में पहले स्निप किए गए संकेत के रूप में संस्करणित है। – zbig

+0

मैंने जांच की कि यह 'व्यक्ति' पर '@ Vesion' कॉलम के बिना कैसे व्यवहार करेगा और यह लॉकिंग पर असफल होगा। * AssertionFailure के साथ हाइबरनेट: गैर-संस्करण वाली इकाई पर संस्करण वृद्धि को मजबूर नहीं कर सकता * और Eclipselink * PersistenceException के साथ: अमान्य लॉक मोड प्रकार उस इकाई के लिए जिस पर संस्करण लॉकिंग इंडेक्स नहीं है। जब कोई संस्करण लॉकिंग इंडेक्स नहीं होता है तो केवल एक संभावित लॉक मोड प्रकार का उपयोग किया जा सकता है। * – zbig

0

के रूप में समझाया this post में, LockModeType.OPTIMICTIC जांच-कार्य संबंधी समस्याओं से ग्रस्त है ताकि आप better off coupling it with a PESSIMISTIC_READ or PESSIMISTIC_WRITE हैं।

दूसरी तरफ, LockModeType.OPTIMICTIC_FORCE_INCREMENT किसी भी डेटा असंगतता समस्या से पीड़ित नहीं है, और जब भी कोई बच्चा इकाई संशोधित होती है तो आप आमतौर पर मूल इकाई के संस्करण को नियंत्रित करने के लिए इसका उपयोग करेंगे। बाहर this article आप कैसे उपयोग कर सकते हैं LockModeType.OPTIMICTIC_FORCE_INCREMENT या LockModeType.PESSIMISTIC_FORCE_INCREMENT तो माता-पिता को ध्यान बच्चे इकाई में इकाई संस्करण की कहानियों के साथ-साथ बदल जाता है कि अधिक जानकारी के लिए

चेक।

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