जावा - जेपीए - @Version एनोटेशन


118

@Versionजेपीए में एनोटेशन कैसे काम करता है ?

मुझे विभिन्न उत्तर मिले जिनका अर्क निम्नानुसार है:

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

लेकिन मुझे अभी भी यकीन नहीं है कि यह कैसे काम करता है।


निम्नलिखित पंक्तियों से भी:

आपको संस्करण क्षेत्रों को अपरिवर्तनीय मानना ​​चाहिए। फ़ील्ड मान को बदलने से अपरिभाषित परिणाम होते हैं।

क्या इसका मतलब है कि हमें अपना संस्करण क्षेत्र घोषित करना चाहिए final?


1
यह सब हर अपडेट क्वेरी में संस्करण की जांच / अद्यतन करता है UPDATE myentity SET mycolumn = 'new value', version = version + 1 WHERE version = [old.version]:। यदि किसी ने रिकॉर्ड को अपडेट किया है, तो old.versionवह अब डीबी में एक से मेल नहीं खाएगा और जहां क्लॉज अपडेट को होने से रोकेगा। 'अपडेट की गई पंक्तियाँ' होंगी 0, जिसे जेपीए निष्कर्ष निकाल सकता है कि एक समवर्ती संशोधन हुआ।
स्टिजन डे विट

जवाबों:


189

लेकिन फिर भी मुझे यकीन नहीं है कि यह कैसे काम करता है?

मान लीजिए कि किसी इकाई के MyEntityपास एक एनोटेट versionसंपत्ति है:

@Entity
public class MyEntity implements Serializable {    

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @Version
    private Long version;

    //...
}

अद्यतन करने पर, एनोटेट किए गए फ़ील्ड को बढ़ा दिया @Versionजाएगा और WHEREइसे कुछ इस तरह जोड़ा जाएगा :

UPDATE MYENTITY SET ..., VERSION = VERSION + 1 WHERE ((ID = ?) AND (VERSION = ?))

यदि WHEREखंड रिकॉर्ड से मेल खाने में विफल रहता है (क्योंकि एक ही इकाई पहले से ही किसी अन्य थ्रेड द्वारा अद्यतन की गई है), तो दृढ़ता प्रदाता एक फेंक देगा OptimisticLockException

क्या इसका मतलब है कि हमें अपने संस्करण क्षेत्र को अंतिम घोषित करना चाहिए

नहीं, लेकिन आप सेटर को संरक्षित बनाने पर विचार कर सकते हैं क्योंकि आप इसे कॉल करने वाले नहीं हैं।


5
मुझे कोड के इस टुकड़े के साथ एक शून्य-पॉइंटर अपवाद मिला, क्योंकि अशक्त के रूप में लंबे इनिशियल्स को संभवतः 0 एल के साथ प्रारंभिक रूप से प्रारंभ किया जाना चाहिए।
मार्कस

2
ऑटो-अनबॉक्सिंग पर longया केवल इस longValue()पर कॉल करने पर भरोसा न करें । आपको स्पष्ट nullजांच की आवश्यकता है । स्पष्ट रूप से इसे स्वयं शुरू करना मैं ऐसा नहीं करूंगा क्योंकि यह क्षेत्र ORM प्रदाता द्वारा प्रबंधित किया जाना चाहिए। मुझे लगता है कि यह 0Lडीबी में पहली बार डालने पर सेट हो जाता है , इसलिए यदि यह इसके लिए सेट nullहै तो आपको बताता है कि यह रिकॉर्ड अभी तक कायम नहीं हुआ है।
स्टिजेन डे विट

क्या यह एक से अधिक बार बनाई गई इकाई (बनाने की कोशिश) को बनने से रोकेगा? मेरा मतलब है कि एक जेएमएस विषय संदेश एक इकाई के निर्माण को ट्रिगर करता है और संदेश के लिए एक आवेदन के कई उदाहरण हैं। मैं केवल अद्वितीय बाधा उल्लंघन से बचना चाहता हूं ..
मनु

क्षमा करें, मुझे पता है कि यह एक पुराना धागा है, लेकिन @Version भी क्लस्टर वातावरण में गंदे कैश को ध्यान में रखता है?
शॉन एयोन स्मिथ

3
यदि स्प्रिंग डेटा JPA का उपयोग करते हैं, तो क्षेत्र के लिए Longएक आदिम के बजाय एक आवरण का उपयोग करना बेहतर हो सकता है , क्योंकि संभवतः एक शून्य संस्करण फ़ील्ड को एक संकेतक के रूप में माना जाएगा कि इकाई नया है। यदि इकाई नई है (जैसा कि संस्करण शून्य होने का संकेत दिया गया है), स्प्रिंग कॉल करेगा । लेकिन अगर संस्करण का मूल्य है, तो यह कॉल करेगा । यह भी एक संस्करण क्षेत्र है कि एक आवरण प्रकार के रूप में घोषित किया जाता है, क्योंकि इसे अनैतिक रूप से छोड़ दिया जाना चाहिए। long@VersionSimpleJpaRepository.save(entity)em.persist(entity)em.merge(entity)
rdguam

33

हालाँकि @ पास्कल का उत्तर पूरी तरह से मान्य है, मेरे अनुभव से मुझे आशावादी लॉकिंग को पूरा करने के लिए मददगार कोड नीचे मिल गया है:

@Entity
public class MyEntity implements Serializable {    
    // ...

    @Version
    @Column(name = "optlock", columnDefinition = "integer DEFAULT 0", nullable = false)
    private long version = 0L;

    // ...
}

क्यों? इसलिये:

  1. यदि गलती से सेट किया गया है तो ऑप्टिमिस्टिक लॉकिंग काम नहीं करेगा@Versionnull
  2. के रूप में इस विशेष क्षेत्र जरूरी वस्तु का एक व्यावसायिक संस्करण नहीं है, एक भ्रामक से बचने के लिए, मैं इस तरह के क्षेत्र को नाम के optlockबजाय कुछ पसंद करता हूं version

पहले बिंदु से कोई फर्क नहीं पड़ता कि डेटाबेस में डेटा डालने के लिए एप्लिकेशन केवल JPA का उपयोग करता है, क्योंकि JPA विक्रेता निर्माण समय पर फ़ील्ड के 0लिए लागू करेगा @version। लेकिन लगभग हमेशा सादे एसक्यूएल बयान भी उपयोग में हैं (कम से कम इकाई और एकीकरण परीक्षण के दौरान)।


मैं इसे u_lmod(उपयोगकर्ता द्वारा संशोधित अंतिम) कहता हूं, जहां उपयोगकर्ता एक मानव या परिभाषित (स्वचालित) प्रक्रिया / इकाई / ऐपu_lmod_id हो सकता है (इसलिए अतिरिक्त रूप से भी भंडारण कर सकता है)। (यह मेरे विचार में एक बहुत ही बुनियादी व्यवसाय-मेटा-विशेषता है)। यह आमतौर पर UTC में DATE (TIME) (वर्ष के बारे में अर्थ ... मिलिस) के रूप में इसका मान संग्रहीत कर रहा है (यदि संपादक का समय क्षेत्र "स्थान" स्टोर करने के लिए महत्वपूर्ण है तो timezone के साथ)। इसके अलावा DWH सिंक परिदृश्यों के लिए बहुत उपयोगी है।
एंड्रियास डिट्रिच

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

अच्छा बिंदु दिमित्री, धन्यवाद, हालांकि जब यह IMHO संस्करण की बात आती है तो यह वास्तव में कोई मायने नहीं रखता है।
जी डेमेकी

9

हर बार जब कोई इकाई डेटाबेस में अपडेट की जाती है, तो संस्करण फ़ील्ड एक से बढ़ जाएगी। डेटाबेस में इकाई को अपडेट करने वाले प्रत्येक ऑपरेशन ने WHERE version = VERSION_THAT_WAS_LOADED_FROM_DATABASEइसकी क्वेरी के लिए जोड़ा होगा ।

आपके ऑपरेशन की प्रभावित पंक्तियों की जाँच में jpa फ्रेमवर्क यह सुनिश्चित कर सकता है कि आपकी इकाई को लोड करने और जारी रखने के बीच कोई समवर्ती संशोधन नहीं था क्योंकि क्वेरी को डेटाबेस में आपकी इकाई नहीं मिलेगी जब यह लोड और हठ के बीच संस्करण संख्या में वृद्धि हुई है।


JPAUpdateQuery के माध्यम से नहीं। इसलिए "डेटाबेस में इकाई को अपडेट करने वाले प्रत्येक ऑपरेशन ने WHERE संस्करण = VERSION_THAT_WAS_LOADED_FROM_DATABASE को इसकी क्वेरी में जोड़ा होगा" सच नहीं है।
पेड्रो बोर्ग्स

2

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

इसलिए इकाई मूल्य को अपडेट करना अधिक सुरक्षित, अधिक आशावादी होगा।

यदि मूल्य बार-बार बदलता है, तो आप संस्करण क्षेत्र का उपयोग नहीं करने पर विचार कर सकते हैं। एक उदाहरण के लिए "एक इकाई जिसमें काउंटर फ़ील्ड है, जो हर बार एक वेब पेज तक पहुंच बढ़ाएगा"


0

बस थोड़ी और जानकारी जोड़ रहे हैं।

जेपीए आपके लिए हुड के तहत संस्करण का प्रबंधन करता है, हालांकि यह ऐसा नहीं करता है जब आप अपने रिकॉर्ड को अपडेट करते हैं JPAUpdateClause, तो ऐसे मामलों में आपको मैन्युअल रूप से संस्करण वृद्धि को क्वेरी में जोड़ना होगा।

उसी को JPQL के माध्यम से अद्यतन करने के बारे में कहा जा सकता है, अर्थात इकाई के लिए एक सरल परिवर्तन नहीं, लेकिन डेटाबेस के लिए एक अद्यतन आदेश भले ही हाइबरनेट द्वारा किया गया हो

पेड्रो


3
क्या है JPAUpdateClause?
कार्ल रिक्टर

अच्छा सवाल है, सरल उत्तर है: खराब उदाहरण :) JPAUpdateClause QueryDSL विशिष्ट है, केवल कोड में किसी इकाई की स्थिति को प्रभावित करने के विपरीत JPQL के साथ एक अद्यतन चलाने के बारे में सोचें।
पेद्रो बोर्ग्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.