2011-03-11 17 views
7

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

/* 
    Hibernate: select receivingg0_.id as id9_14_, receivingg0_.creationDate as creation2_9_14_, ... too long 
    the version before modification : 16 
    the version after modification : 16 
    after merge the modification, the version is : 16 
    Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, usermodify_id=?, ... too long 
    after flushing the modification, the version is finally : 17 
*/ 
public void modifyHeaderAndGetUpdatedVersion() { 
    String id = "3b373f6a-9cd1-4c9c-9d46-240de37f6b0f"; 
    ReceivingGood receivingGood = em.find(ReceivingGood.class, id); 
    System.out.println("the version before modification : " + receivingGood.getVersion()); 

    receivingGood.setTransactionNumber("NUM001xyz"); 
    System.out.println("the version after modification : " + receivingGood.getVersion()); 

    receivingGood = em.merge(receivingGood); 
    System.out.println("after merge the modification, the version is : " + receivingGood.getVersion()); 

    em.flush(); 
    System.out.println("after flushing the modification, the version is finally : " + receivingGood.getVersion()); 
} 

अपने परीक्षण में, संस्करण फ्लश के बाद वृद्धि की जाती गया: डी


यहाँ एक सरल कोड है और यह भी टिप्पणी के रूप में उत्पादन है। विलय ऑपरेशन से लौटाया गया उदाहरण में वृद्धि संस्करण नहीं है।

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


क्या कोई तरीका है जहां मैं फ्लश किए बिना नवीनतम संस्करण प्राप्त कर सकता हूं?

धन्यवाद!


अद्यतन


मेरे अनुभव में, इस मैन्युअल रूप से बढ़ाने समस्या हो सकती है के रूप में नीचे इस उदाहरण से देखा जा सकता। इस उदाहरण में, हमारे पास 2 फ्लश हैं।

पहला वाला डीबी कनेक्शन में परिवर्तन सिंक्रनाइज़ करना है, ताकि एक ही कनेक्शन से संग्रहीत प्रक्रिया कॉल इकाई प्रबंधक से किए गए परिवर्तन देख सके।

दूसरा फ्लश अंतिम संस्करण प्राप्त करने के लिए बुलाया जाता है। और हम देख सकते हैं कि यह दो बार बढ़ गया है। इसलिए फ्लैशिंग के बिना मैन्युअल वृद्धि से संस्करण प्राप्त करना इस स्थिति में काम नहीं करेगा, क्योंकि हमें वास्तव में गिनना है कि कितने फ्लश किए जा रहे हैं।

/* 
Hibernate: select receivingg0_.id as id9_14_, receivingg0_.creationDate as creation2_9_14_, .. too long 
the version before modification : 18 
the version after modification : 18 
after merge the modification, the version is : 18 
now flushing the modification, so that the stored procedure call from the same connection can see the changes 
Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, .. too long 
after flushing the modification, the version is : 19 
Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, .. too long 
after the second flush, the version got increased again into : 20 
*/ 
public void modifyHeaderAndGetUpdatedVersionWith2Flushes() { 
    String id = "3b373f6a-9cd1-4c9c-9d46-240de37f6b0f"; 
    ReceivingGood receivingGood = em.find(ReceivingGood.class, id); 
    System.out.println("the version before modification : " + receivingGood.getVersion()); 

    //auditEntity(receivingGood, getUser("3978fee3-9690-4377-84bd-9fb05928a6fc")); 
    receivingGood.setTransactionNumber("NUM001xyz"); 
    System.out.println("the version after modification : " + receivingGood.getVersion()); 

    receivingGood = em.merge(receivingGood); 
    System.out.println("after merge the modification, the version is : " + receivingGood.getVersion()); 
    System.out.println("now flushing the modification, so that the stored procedure call from the same connection can see the changes"); 
    em.flush(); 
    System.out.println("after flushing the modification, the version is : " + receivingGood.getVersion()); 

    receivingGood.setTransactionNumber("NUM001abc"); 

    em.flush(); 
    System.out.println("after the second flush, the version got increased again into : " + receivingGood.getVersion()); 
} 

इसका मतलब मैं सच में अंत में फ्लश पर निर्भर करने के लिए संशोधित इकाई के लिए नवीनतम संस्करण प्राप्त करने है?


अद्यतन 2


यहाँ एक सेवा विधि है कि ReceivingGood इकाई अपडेट हो जाएगा और एक डीटीओ नवीनतम संस्करण है कि लौटना चाहिए का एक सरल उदाहरण है।

@Transactional 
public ReceivingGoodDTO doSomethingInTheServiceAndReturnDTO() { 
    // do xxx .. 
    // do yyy .. 
    dto = update(entity); 
    return dto; // and the transaction commits here, but dto's version isnt increased because it's not a managed entity, just a plain POJO 
} 

उत्तर

5

मैं फिर से हाइबरनेट के बारे में अधिक पढ़ने की सिफारिश करता हूं और यह कैसे काम करता है, इसे अपने दस्तावेज़ीकरण या "हाइबरनेट के साथ जावा पर्सिस्टेंस" द्वारा किया जाए।

आप इसे फ्लश ऑपरेशन में देख रहे हैं क्योंकि वह डेटाबेस अपडेट होता है। यदि आप बस फ्लश छोड़ देते हैं और लेनदेन करते हैं, तो आप वही व्यवहार देखेंगे। मतलब, जब भी आपकी इकाई का काम खत्म हो जाता है, हाइबरनेट डेटाबेस में परिवर्तनों को फ्लश करेगा। यह इस चरण में है कि हाइबरनेट संस्करण संख्या की तुलना और अद्यतन करता है। यदि डेटाबेस संस्करण 17 है और आप संस्करण 16 को अपडेट कर रहे हैं, तो एक बाबा ऑब्जेक्ट को अपडेट करने के बारे में, हाइबरनेट एक अपवाद फेंक देगा।

उस ने कहा, आप "भविष्यवाणी" कर सकते हैं कि आपके संस्करण में वर्तमान में मौजूद मूल्य पर 1 को बढ़ाकर अगला संस्करण क्या होगा। लेकिन यह कभी भी वास्तविक नहीं होगा, क्योंकि डेटाबेस रिकॉर्ड को अपडेट करने से पहले यह केवल प्रभावी ढंग से बढ़ता जा रहा है। इसलिए, जब तक आप डेटाबेस से पूछताछ नहीं करते हैं, तब तक कोई समवर्ती परिवर्तन आपके धागे पर दिखाई नहीं देगा।

संपादित करें:

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

यह कहा गया है कि यह तकनीक ध्यान में रखी जानी चाहिए कि इस तकनीक को हाइबरनेट द्वारा प्रबंधित किया जाना चाहिए। आपको इसे अपने आप से नहीं बढ़ाया जाना चाहिए। इस तरह के खेतों के लिए सेटर्स प्रदान नहीं करना अक्सर एक अच्छा अभ्यास है।

दूसरे शब्दों में: आपको "संस्करण" को केवल पढ़ने योग्य मान के रूप में मानना ​​चाहिए और आपके पास इसका कोई नियंत्रण नहीं है। इसलिए, उपयोगकर्ता के लिए अपने मूल्य ऑन-स्क्रीन को प्रदर्शित करना सुरक्षित है, लेकिन इसे कुशल बनाने में सक्षम नहीं है (या अगले संस्करण को "निर्धारित करें")। अधिकतर, आप "सर्वश्रेष्ठ अनुमान" बना सकते हैं, यह अनुमान लगाते हुए कि यह current_version + 1 होगा।

+0

@partenon: मैं समझता हूं कि कैसे काम करता है और काम करता है, और संस्करण उनके द्वारा कैसे बढ़ाया गया है। लेकिन फिर भी मैं आपके द्वारा अनुशंसित पुस्तक को पढ़ूंगा :-) वैसे भी, मैंने मैन्युअल वृद्धि के संबंध में कुछ अतिरिक्त चिंताओं के लिए अपनी मूल पोस्ट अपडेट की है। हमेशा की तरह धन्यवाद। – bertie

+0

मैंने अभी आपकी नई चिंताओं को हल करने के लिए उत्तर अपडेट किया है :-) – jpkrohling

+1

@partenon: तो, मैं अंत में निष्कर्ष निकाल सकता हूं कि, सक्रिय लेनदेन के अंदर एक डीटीओ बनाने के लिए जो नवीनतम संस्करण के साथ इकाई को प्रतिबिंबित करता है, मुझे वास्तव में करना है फ्लश()। धन्यवाद ! – bertie

0

नवीनतम संस्करण वर्तमान एक + 1. आप entityToDto में संस्करण अपने आप को बढ़ा सकता है() विधि है:

public ReceivingGoodDTO update(ReceivingGood entity) { 
    // merge it 
    entity = entityManager.merge(entity); 

    // the version is not incremented yet, so do the flush to increment the version 
    entityManager.flush(); // if i dont do this, the dto below will get the unincremented one 

    // use a mapper, maybe like dozer, to copy the properties from the entity to the dto object, including the newest version of that entity 
    ReceivingGoodDTO dto = mapper.map(entity, dto); 

    return dto; 
} 

और यहाँ एक उदाहरण है कि विधि का उपयोग करता है।

लेकिन आपके उदाहरण में, फ्लश करने से ऐसी प्रदर्शन समस्या नहीं आती है, आईएमओ, क्योंकि हाइबरनेट इसे प्रतिबद्ध समय पर वैसे भी करेगा। दो फ्लश होंगे, लेकिन दूसरे के पास अब फ्लश करने के लिए कुछ भी नहीं होगा।

+0

हैलो 2, मैंने मैन्युअल वृद्धि के संबंध में कुछ अतिरिक्त चिंताओं के लिए अपनी मूल पोस्ट अपडेट की है। – bertie

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