चूंकि यह एक बहुत ही सामान्य प्रश्न है, इसलिए मैंने यह लेख लिखा है
, जिस पर यह उत्तर आधारित है।
इकाई राज्यों
जेपीए निम्नलिखित इकाई राज्यों को परिभाषित करता है:
नया (क्षणिक)
एक नई बनाई गई वस्तु जो कभी भी एक हाइबरनेट Session
(उर्फ Persistence Context
) के साथ संबद्ध नहीं हुई है और किसी भी डेटाबेस तालिका पंक्ति में मैप नहीं की गई है जिसे नई (क्षणिक) स्थिति में माना जाता है।
लगातार बने रहने के लिए हमें या तो स्पष्ट रूप से EntityManager#persist
विधि को बुलाना होगा या सकर्मक दृढ़ता का प्रयोग करना होगा।
स्थायी (प्रबंधित)
एक स्थायी इकाई को डेटाबेस तालिका पंक्ति के साथ जोड़ा गया है और इसे वर्तमान में चल रहे परिप्रेक्ष्य द्वारा प्रबंधित किया जा रहा है। ऐसी इकाई में किए गए किसी भी परिवर्तन को डेटाबेस में (सत्र फ्लश-टाइम के दौरान) पहचाना और प्रचारित किया जा रहा है।
हाइबरनेट के साथ, हमें अब INSERT / UPDATE / DELETE कथनों को निष्पादित नहीं करना है। हाइबरनेट एक व्यवहारिक लिखने के पीछे काम करने की शैली को नियोजित करता है और वर्तमान Session
फ्लश-टाइम के दौरान परिवर्तनों को अंतिम अंतिम क्षण में सिंक्रनाइज़ किया जाता है ।
जुदा जुदा
एक बार वर्तमान में चल रहे पर्सेंटेज कॉन्सेप्ट को बंद करने के बाद सभी पहले से प्रबंधित इकाइयां अलग हो जाती हैं। क्रमिक परिवर्तनों को अब ट्रैक नहीं किया जाएगा और कोई स्वचालित डेटाबेस सिंक्रनाइज़ेशन नहीं होने वाला है।
इकाई अवस्था परिवर्तन
आप EntityManager
इंटरफ़ेस द्वारा परिभाषित विभिन्न विधियों का उपयोग करके इकाई स्थिति को बदल सकते हैं ।
जेपीए इकाई की स्थिति को बेहतर ढंग से समझने के लिए, निम्नलिखित चित्र पर विचार करें:
JPA का उपयोग करते समय, एक सक्रिय करने के लिए एक अलग इकाई को पुन: व्यवस्थित करने के लिए EntityManager
, आप मर्ज ऑपरेशन का उपयोग कर सकते हैं ।
मूल हाइबरनेट एपीआई का उपयोग करते समय, इसके अलावा merge
, आप एक अलग इकाई को एक सक्रिय हाइबरनेट को अपडेट करने के लिए अलग कर सकते हैं, जैसा कि निम्नलिखित चित्र द्वारा दिखाया गया है:
एक अलग इकाई विलय
मर्ज किसी निकाय निकाय स्थिति (स्रोत) की प्रतिलिपि किसी प्रबंधित निकाय आवृत्ति (गंतव्य) पर करने जा रहा है।
विचार करें कि हमने निम्नलिखित Book
इकाई को बनाए रखा है , और अब इकाई को अलग EntityManager
कर दिया गया है क्योंकि इकाई को बंद रखने के लिए इसका उपयोग किया गया था:
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
return book;
});
जबकि इकाई अलग अवस्था में है, हम इसे निम्नानुसार संशोधित करते हैं:
_book.setTitle(
"High-Performance Java Persistence, 2nd edition"
);
अब, हम डेटाबेस में परिवर्तन करना चाहते हैं, इसलिए हम merge
विधि को कॉल कर सकते हैं :
doInJPA(entityManager -> {
Book book = entityManager.merge(_book);
LOGGER.info("Merging the Book entity");
assertFalse(book == _book);
});
और हाइबरनेट निम्नलिखित SQL कथनों को निष्पादित करने जा रहा है:
SELECT
b.id,
b.author AS author2_0_,
b.isbn AS isbn3_0_,
b.title AS title4_0_
FROM
book b
WHERE
b.id = 1
-- Merging the Book entity
UPDATE
book
SET
author = 'Vlad Mihalcea',
isbn = '978-9730228236',
title = 'High-Performance Java Persistence, 2nd edition'
WHERE
id = 1
यदि विलय इकाई में वर्तमान में कोई समतुल्य नहीं है EntityManager
, तो डेटाबेस से एक ताजा इकाई स्नैपशॉट प्राप्त किया जाएगा।
एक बार जब एक मानव इकाई होती है, तो जेपीए उस निकाले गए राज्य की स्थिति की प्रतिलिपि उसी पर बनाता है जिसे वर्तमान में प्रबंधित किया गया है, और हठ प्रसंग केflush
दौरान , एक अद्यतन उत्पन्न किया जाएगा यदि गंदा जाँच तंत्र पाता है कि प्रबंधित इकाई बदल गई है।
इसलिए, उपयोग करते समय merge
, अलग किए गए ऑब्जेक्ट का उदाहरण मर्ज ऑपरेशन के बाद भी अलग होना जारी रहेगा।
एक अलग इकाई को फिर से प्रशिक्षित करना
हाइबरनेट, लेकिन नहीं जेपीए update
विधि के माध्यम से रिटेटिंग का समर्थन करता है ।
एक हाइबरनेट Session
केवल एक इकाई ऑब्जेक्ट को किसी दिए गए डेटाबेस पंक्ति के लिए संबद्ध कर सकता है। ऐसा इसलिए है क्योंकि पर्सेंटेज कॉन्सेप्ट एक इन-मेमोरी कैश (प्रथम स्तर कैश) के रूप में कार्य करता है और केवल एक मान (इकाई) एक दिए गए कुंजी (इकाई प्रकार और डेटाबेस पहचानकर्ता) के साथ जुड़ा हुआ है।
एक इकाई को तब ही बदला जा सकता है जब कोई अन्य JVM ऑब्जेक्ट (समान डेटाबेस पंक्ति से मेल खाता हो) जो पहले से ही हाइबरनेट के साथ जुड़ा हुआ है Session
।
ध्यान में रखते हुए हमने Book
इकाई को बनाए रखा है और जब Book
इकाई अलग अवस्था में थी तब हमने इसे संशोधित किया था:
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
return book;
});
_book.setTitle(
"High-Performance Java Persistence, 2nd edition"
);
हम इस तरह से अलग की गई इकाई को पुनः प्राप्त कर सकते हैं:
doInJPA(entityManager -> {
Session session = entityManager.unwrap(Session.class);
session.update(_book);
LOGGER.info("Updating the Book entity");
});
और हाइबरनेट निम्नलिखित SQL कथन को निष्पादित करेगा:
-- Updating the Book entity
UPDATE
book
SET
author = 'Vlad Mihalcea',
isbn = '978-9730228236',
title = 'High-Performance Java Persistence, 2nd edition'
WHERE
id = 1
update
विधि करने की आवश्यकता है एक हाइबरनेट करने के लिए ।unwrap
EntityManager
Session
इसके विपरीत merge
, प्रदान की गई अलग इकाई को वर्तमान दृढ़ता के संदर्भ के साथ फिर से जोड़ा जा रहा है और फ्लश के दौरान एक अद्यतन निर्धारित किया जाता है कि इकाई संशोधित हुई है या नहीं।
इसे रोकने के लिए, आप @SelectBeforeUpdate
हाइबरनेट एनोटेशन का उपयोग कर सकते हैं जो कि एक सेलेक्ट स्टेटमेंट को ट्रिगर करेगा जो कि लोड की गई स्थिति को प्राप्त करता है जो फिर गंदे जाँच तंत्र द्वारा उपयोग किया जाता है।
@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {
//Code omitted for brevity
}
NonUniqueObjectException से सावधान रहें
इसके साथ होने वाली एक समस्या यह है कि update
अगर हठ प्रसंग में पहले से ही आईडी के साथ और निम्न उदाहरण में एक ही प्रकार के साथ एक इकाई संदर्भ शामिल है:
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
Session session = entityManager.unwrap(Session.class);
session.saveOrUpdate(book);
return book;
});
_book.setTitle(
"High-Performance Java Persistence, 2nd edition"
);
try {
doInJPA(entityManager -> {
Book book = entityManager.find(
Book.class,
_book.getId()
);
Session session = entityManager.unwrap(Session.class);
session.saveOrUpdate(_book);
});
} catch (NonUniqueObjectException e) {
LOGGER.error(
"The Persistence Context cannot hold " +
"two representations of the same entity",
e
);
}
अब, जब ऊपर परीक्षण मामले को निष्पादित किया जाता है, तो हाइबरनेट फेंकने जा रहा है NonUniqueObjectException
क्योंकि दूसरे में EntityManager
पहले Book
से ही एक पहचानकर्ता के साथ एक इकाई है जिस पर हम गुजरते हैं update
, और दृढ़ता संदर्भ एक ही इकाई के दो प्रतिनिधित्व नहीं कर सकता है।
org.hibernate.NonUniqueObjectException:
A different object with the same identifier value was already associated with the session : [com.vladmihalcea.book.hpjp.hibernate.pc.Book#1]
at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:651)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:284)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:227)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:682)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:674)
निष्कर्ष
merge
विधि अगर आप आशावादी लॉकिंग का उपयोग कर रहे हैं क्योंकि यह आप खो अपडेट रोकने के लिए अनुमति देता है पसंद किया जा रहा है। इस विषय के बारे में अधिक जानकारी के लिए, इस लेख को देखें ।
update
के रूप में यह अतिरिक्त SELECT कथन द्वारा उत्पन्न रोका जा सकता है बैच के अपडेट के लिए अच्छा है merge
आपरेशन, इसलिए बैच अद्यतन निष्पादन समय को कम करने।
refresh()
अलग-अलग संस्थाओं पर अनुमति नहीं देती है? 2.0 युक्ति के माध्यम से देखने से मुझे कोई औचित्य नहीं दिखता है; बस इसकी अनुमति नहीं है।