जैसा कि मैंने इस लेख में बताया है , आपको अधिकांश समय जेपीए विधियों और update
बैच प्रसंस्करण कार्यों के लिए पसंद करना चाहिए ।
एक जेपीए या हाइबरनेट इकाई निम्नलिखित चार राज्यों में से एक में हो सकती है:
- क्षणिक (नया)
- प्रबंधित (लगातार)
- जुदा जुदा
- हटाया (हटाए गए)
एक राज्य से दूसरे में संक्रमण EntityManager या सत्र विधियों के माध्यम से किया जाता है।
उदाहरण के लिए, जेपीए EntityManager
निम्नलिखित इकाई राज्य संक्रमण के तरीके प्रदान करता है।
हाइबरनेट Session
सभी जेपीए EntityManager
विधियों को लागू करता है और कुछ अतिरिक्त इकाई राज्य संक्रमण विधियों जैसे save
, saveOrUpdate
और प्रदान करता है update
।
दृढ़ रहना
ट्रांसिएंट (नया) से प्रबंधित (स्थायी) के लिए एक इकाई की स्थिति को बदलने के लिए, हम persist
जेपीए द्वारा प्रस्तुत विधि का उपयोग कर सकते हैं EntityManager
जो कि हाइबरनेट द्वारा विरासत में मिला है Session
।
यह persist
विधि हाइबरनेट इवेंट श्रोता PersistEvent
द्वारा नियंत्रित की जाती DefaultPersistEventListener
है।
इसलिए, निम्नलिखित परीक्षण मामले को निष्पादित करते समय:
doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
LOGGER.info(
"Persisting the Book entity with the id: {}",
book.getId()
);
});
हाइबरनेट निम्नलिखित SQL कथन उत्पन्न करता है:
CALL NEXT VALUE FOR hibernate_sequence
-- Persisting the Book entity with the id: 1
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
ध्यान दें कि इकाई को वर्तमान दृढ़ता संदर्भ में id
संलग्न करने से पहले सौंपा गया है Book
। यह आवश्यक है क्योंकि प्रबंधित इकाइयां एक Map
संरचना में संग्रहीत होती हैं जहां कुंजी इकाई प्रकार और उसके पहचानकर्ता द्वारा बनाई जाती है और मूल्य इकाई संदर्भ होता है। यही कारण है कि जेपीए EntityManager
और हाइबरनेट Session
को प्रथम-स्तरीय कैश के रूप में जाना जाता है।
कॉल करते समय persist
, इकाई केवल वर्तमान में चल रहे परिप्रेक्ष्य से जुड़ी होती है, और INSERT flush
को कॉल किए जाने तक स्थगित किया जा सकता है।
एकमात्र अपवाद पहचान जनरेटर है जो तुरंत INSERT को ट्रिगर करता है क्योंकि यह एकमात्र तरीका है जिससे यह इकाई पहचानकर्ता प्राप्त कर सकता है। इस कारण से, हाइबरनेट IDENTITY जनरेटर का उपयोग कर संस्थाओं के लिए बैच आवेषण नहीं कर सकता है। इस विषय के बारे में अधिक जानकारी के लिए, इस लेख को देखें ।
सहेजें
हाइबरनेट-विशिष्ट save
विधि जेपीए से पहले की है और यह हाइबरनेट परियोजना की शुरुआत के बाद से उपलब्ध है।
यह save
विधि हाइबरनेट इवेंट श्रोता SaveOrUpdateEvent
द्वारा नियंत्रित की जाती DefaultSaveOrUpdateEventListener
है। इसलिए, save
विधि update
और saveOrUpdate
विधियों के बराबर है ।
यह देखने के लिए कि save
विधि कैसे काम करती है, निम्नलिखित परीक्षण मामले पर विचार करें:
doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
Session session = entityManager.unwrap(Session.class);
Long id = (Long) session.save(book);
LOGGER.info(
"Saving the Book entity with the id: {}",
id
);
});
ऊपर परीक्षण केस चलाते समय, हाइबरनेट निम्नलिखित SQL कथन उत्पन्न करता है:
CALL NEXT VALUE FOR hibernate_sequence
-- Saving the Book entity with the id: 1
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
जैसा कि आप देख सकते हैं, परिणाम persist
विधि कॉल के समान है । हालाँकि, इसके विपरीत persist
, save
विधि निकाय पहचानकर्ता देता है।
अधिक जानकारी के लिए, इस लेख को देखें ।
अपडेट करें
हाइबरनेट-विशिष्ट update
विधि का अर्थ है गंदे चेकिंग तंत्र को बायपास करना और फ्लश समय पर एक इकाई अद्यतन को मजबूर करना।
यह update
विधि हाइबरनेट इवेंट श्रोता SaveOrUpdateEvent
द्वारा नियंत्रित की जाती DefaultSaveOrUpdateEventListener
है। इसलिए, update
विधि save
और saveOrUpdate
विधियों के बराबर है ।
यह देखने के लिए कि update
विधि कैसे काम करती है, निम्नलिखित उदाहरण पर विचार करें जो Book
एक लेन-देन में एक इकाई को बनाए रखता है, फिर यह तब संशोधित करता है जब इकाई अलग स्थिति में होती है, और यह update
विधि कॉल का उपयोग करके SQL UPDATE को बाध्य करता है ।
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
return book;
});
LOGGER.info("Modifying the Book entity");
_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 कथन उत्पन्न करता है:
CALL NEXT VALUE FOR hibernate_sequence
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
-- Modifying the Book entity
-- Updating the Book entity
UPDATE
book
SET
author = 'Vlad Mihalcea',
isbn = '978-9730228236',
title = 'High-Performance Java Persistence, 2nd edition'
WHERE
id = 1
ध्यान दें कि UPDATE
प्रतिबद्धताओं के संदर्भ में, दृढ़ता से पहले फ्लश के दौरान निष्पादित किया जाता है, और इसीलिए Updating the Book entity
संदेश पहले लॉग किया जाता है।
@SelectBeforeUpdate
अनावश्यक अपडेट से बचने के लिए उपयोग करना
अब, अद्यतन हमेशा निष्पादित किया जा रहा है भले ही इकाई को अलग-थलग अवस्था में नहीं बदला गया हो। इसे रोकने के लिए, आप @SelectBeforeUpdate
हाइबरनेट एनोटेशन का उपयोग कर सकते हैं जो एक SELECT
बयान को ट्रिगर करेगा loaded state
जो कि फिर गंदे जाँच तंत्र द्वारा उपयोग किया जाता है।
इसलिए, यदि हम एनोटेशन के Book
साथ इकाई को एनोटेट करते @SelectBeforeUpdate
हैं:
@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {
//Code omitted for brevity
}
और निम्नलिखित परीक्षण मामले को निष्पादित करें:
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
return book;
});
doInJPA(entityManager -> {
Session session = entityManager.unwrap(Session.class);
session.update(_book);
});
हाइबरनेट निम्नलिखित SQL कथनों को निष्पादित करता है:
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
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
ध्यान दें कि, इस बार, UPDATE
हाइबरनेट गंदे चेकिंग तंत्र से पता चला है कि इकाई को संशोधित नहीं किया गया था , इसलिए कोई क्रियान्वित नहीं किया गया है।
SaveOrUpdate
हाइबरनेट-विशिष्ट saveOrUpdate
विधि के लिए एक उपनाम है save
और update
।
यह saveOrUpdate
विधि हाइबरनेट इवेंट श्रोता SaveOrUpdateEvent
द्वारा नियंत्रित की जाती DefaultSaveOrUpdateEventListener
है। इसलिए, update
विधि save
और saveOrUpdate
विधियों के बराबर है ।
अब, आप saveOrUpdate
तब उपयोग कर सकते हैं जब आप एक इकाई को बनाए रखना चाहते हैं या 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");
doInJPA(entityManager -> {
Session session = entityManager.unwrap(Session.class);
session.saveOrUpdate(_book);
});
से सावधान रहें NonUniqueObjectException
एक समस्या यह है कि साथ हो सकता है save
, update
और saveOrUpdate
अगर हठ संदर्भ पहले से ही एक ही आईडी वाले और निम्न उदाहरण में एक ही प्रकार के एक इकाई संदर्भ शामिल है:
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)
मर्ज
से बचने के लिए NonUniqueObjectException
, आपको merge
जेपीए द्वारा प्रस्तुत विधि का उपयोग करने की आवश्यकता है EntityManager
और Session
साथ ही हाइबरनेट द्वारा विरासत में मिला है ।
जैसा कि इस लेख में बताया गया है , merge
डेटाबेस से एक नया निकाय प्राप्त होता है यदि पर्सिस्टेंस संदर्भ में कोई इकाई संदर्भ नहीं मिलता है, और यह merge
विधि को पारित किए गए अलग किए गए इकाई की स्थिति को कॉपी करता है ।
यह merge
विधि हाइबरनेट इवेंट श्रोता MergeEvent
द्वारा नियंत्रित की जाती DefaultMergeEventListener
है।
यह देखने के लिए कि merge
विधि कैसे काम करती है निम्नलिखित उदाहरण पर विचार करें जो Book
एक लेनदेन में एक इकाई को बनाए रखता है, फिर यह इसे संशोधित करता है, जबकि इकाई अलग राज्य में होती है, और merge
बाद की इकाई को एक अनुशीलन परिप्रेक्ष्य संदर्भ में पारित करता है ।
Book _book = doInJPA(entityManager -> {
Book book = new Book()
.setIsbn("978-9730228236")
.setTitle("High-Performance Java Persistence")
.setAuthor("Vlad Mihalcea");
entityManager.persist(book);
return book;
});
LOGGER.info("Modifying the Book entity");
_book.setTitle(
"High-Performance Java Persistence, 2nd edition"
);
doInJPA(entityManager -> {
Book book = entityManager.merge(_book);
LOGGER.info("Merging the Book entity");
assertFalse(book == _book);
});
ऊपर परीक्षण केस चलाते समय, हाइबरनेट ने निम्नलिखित एसक्यूएल स्टेटमेंट्स को निष्पादित किया:
INSERT INTO book (
author,
isbn,
title,
id
)
VALUES (
'Vlad Mihalcea',
'978-9730228236',
'High-Performance Java Persistence',
1
)
-- Modifying the Book entity
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
ध्यान दें कि जिस इकाई का संदर्भ दिया गया merge
है, वह उस अलग से अलग है जिसे हमने merge
विधि से पारित किया है ।
अब, हालांकि आपको merge
अलग इकाई स्थिति की प्रतिलिपि बनाते समय जेपीए का उपयोग करना चाहिए , SELECT
बैच प्रसंस्करण कार्य को निष्पादित करते समय अतिरिक्त समस्याग्रस्त हो सकता है।
इस कारण से, आपको update
तब उपयोग करना पसंद करना चाहिए जब आप यह सुनिश्चित कर लें कि वर्तमान में चल रहे पर्सेंटेज कॉन्टेक्स्ट से जुड़ी कोई इकाई संदर्भ नहीं है और अलग किए गए इकाई को संशोधित किया गया है।
इस विषय के बारे में अधिक जानकारी के लिए, इस लेख को देखें ।
निष्कर्ष
एक इकाई को बनाए रखने के लिए, आपको जेपीए persist
पद्धति का उपयोग करना चाहिए । अलग निकाय राज्य की प्रतिलिपि बनाने के लिए, merge
प्राथमिकता दी जानी चाहिए। update
विधि बैच प्रोसेसिंग कार्यों के लिए ही उपयोगी है। save
और saveOrUpdate
करने के लिए सिर्फ उपनाम हैं update
और आप शायद सब पर उन्हें इस्तेमाल नहीं करना चाहिए।
कुछ डेवलपर्स save
तब भी कॉल करते हैं जब इकाई पहले से ही प्रबंधित होती है, लेकिन यह एक गलती है और तब से एक अनावश्यक घटना को ट्रिगर करता है, प्रबंधित संस्थाओं के लिए, अद्यतन स्वचालित रूप से दृढ़ता संदर्भ फ्लश समय पर नियंत्रित किया जाता है।
अधिक जानकारी के लिए, इस लेख को देखें ।