Bu makalede açıkladığım gibi , çoğu zaman JPA yöntemlerini veupdate toplu işlem görevleri için .
Bir JPA veya Hazırda Bekletme varlığı aşağıdaki dört durumdan birinde olabilir:
- Geçici (Yeni)
- Yönetilen (Kalıcı)
- bağımsız
- Kaldırıldı (Silindi)
Bir durumdan diğerine geçiş EntityManager veya Session yöntemleri aracılığıyla yapılır.
Örneğin, JPA EntityManageraşağıdaki varlık durumu geçiş yöntemlerini sağlar.

Hazırda Beklet, Sessiontüm JPA EntityManageryöntemlerini uygular ve save, saveOrUpdateve gibi bazı ek varlık durumu geçiş yöntemleri sağlar update.

Persist
Bir varlığın durumunu Geçici (Yeni) yerine Yönetilen (Kalıcı) olarak değiştirmek için, Hazırda Bekletme tarafından da devralınan persistJPA tarafından sunulan yöntemi kullanabiliriz .EntityManagerSession
persistYöntem, bir tetikler PersistEventile kullanılan ve DefaultPersistEventListenerhazırda olay dinleyicisi.
Bu nedenle, aşağıdaki test senaryosunu yürütürken:
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()
);
});
Hazırda Beklet aşağıdaki SQL deyimlerini oluşturur:
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
)
Varlığın mevcut Kalıcı Bağlam'a ideklenmeden önce atandığına dikkat edin Book. Yönetilen varlıklar Map, anahtarın varlık türü ve tanımlayıcısı tarafından oluşturulduğu ve değerin varlık başvurusu olduğu bir yapıda depolanması nedeniyle bu gereklidir . JPA EntityManagerve Hazırda Bekletme'nin SessionBirinci Düzey Önbellek olarak bilinmesinin nedeni budur .
Arama yaparken persist, varlık yalnızca şu anda çalışmakta olan Kalıcılık Bağlamına eklenir ve INSERT,flush .
Tek istisna, INSERT'i hemen tetikleyen IDENTITY oluşturucusudur, çünkü varlık tanımlayıcısını almanın tek yolu budur. Bu nedenle, Hazırda Bekletme, IDENTITY üretecini kullanan varlıklar için ekleri toplu işleyemez. Bu konu hakkında daha fazla bilgi için bu makaleye göz atın .
Kayıt etmek
Hazırda Bekleme özgü saveyöntem JPA'dan önce gelir ve Hazırda Bekletme projesinin başından beri kullanılabilir.
saveYöntem, bir tetikler SaveOrUpdateEventile kullanılan ve DefaultSaveOrUpdateEventListenerhazırda olay dinleyicisi. Bu nedenle, saveyöntem updateve saveOrUpdateyöntemlerine eşdeğerdir .
saveYöntemin nasıl çalıştığını görmek için aşağıdaki test durumunu göz önünde bulundurun:
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
);
});
Yukarıdaki test senaryosunu çalıştırırken, Hazırda Beklet aşağıdaki SQL deyimlerini oluşturur:
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
)
Gördüğünüz gibi, sonuç persistyöntem çağrısıyla aynıdır . Ancak, aksine persist, saveyöntem varlık tanımlayıcı döndürür.
Daha fazla ayrıntı için bu makaleye göz atın .
Güncelleme
Hazırda Bekletme özelliğine yönelik updateyöntem, kirli denetim mekanizmasını atlamak ve bir varlık sifonunu güncellemeye zorlamak içindir.
updateYöntem, bir tetikler SaveOrUpdateEventile kullanılan ve DefaultSaveOrUpdateEventListenerhazırda olay dinleyicisi. Bu nedenle, updateyöntem saveve saveOrUpdateyöntemlerine eşdeğerdir .
updateYöntemin nasıl çalıştığını görmek için Book, bir işlemde bir varlığa devam eden aşağıdaki örneği göz önünde bulundurun , sonra varlık ayrık durumdayken onu değiştirir ve updateyöntem çağrısını kullanarak SQL GÜNCELLEMESİ'ni zorlar .
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");
});
Yukarıdaki test senaryosunu yürütürken, Hazırda Beklet aşağıdaki SQL deyimlerini oluşturur:
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
UPDATEDevamlılık Bağlamı sırasında, kararlılıktan hemen önce yürütüldüğüne dikkat edin ve bu yüzden önce Updating the Book entitymesaj günlüğe kaydedilir.
@SelectBeforeUpdateGereksiz güncellemeleri önlemek için kullanma
Şimdi, varlık ayrık durumdayken değiştirilmese bile UPDATE her zaman yürütülecektir. Bunu önlemek için , getirilen @SelectBeforeUpdatebir SELECTifadeyi tetikleyecek Hazırda Bekletme notunu kullanabilirsiniz.loaded state ve daha sonra kirli kontrol mekanizması tarafından kullanılan .
Dolayısıyla, Bookvarlığı @SelectBeforeUpdateek açıklama ile eklersek:
@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {
//Code omitted for brevity
}
Ve aşağıdaki test senaryosunu yürütün:
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);
});
Hazırda Bekletme aşağıdaki SQL deyimlerini yürütür:
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
Bu kez, UPDATEHazırda Bekletme kirli denetim mekanizması varlığın değiştirilmediğini algıladığından, yürütülmediğine dikkat edin.
SaveOrUpdate
Hazırda özgü saveOrUpdateyöntem sadece için takma saveve update.
saveOrUpdateYöntem, bir tetikler SaveOrUpdateEventile kullanılan ve DefaultSaveOrUpdateEventListenerhazırda olay dinleyicisi. Bu nedenle, updateyöntem saveve saveOrUpdateyöntemlerine eşdeğerdir .
Şimdi, saveOrUpdatebir varlığı devam ettirmek veya UPDATEaşağıdaki örnekte gösterildiği gibi a'yı zorlamak için kullanabilirsiniz .
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);
});
Dikkat edin NonUniqueObjectException
İle oluşabilir bir problem save, updateve saveOrUpdateSebat Bağlam zaten aynı kimliğe sahip ve aşağıdaki örnekte olduğu gibi aynı tipte bir varlık başvuru içeriyorsa geçerli:
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
);
}
Şimdi, yukarıdaki test senaryosunu yürütürken, Hazırda Beklet öğesi bir atar NonUniqueObjectExceptionçünkü ikincisi EntityManagerzaten Bookgeçtiğimizle aynı tanımlayıcıya sahip bir varlık içerdiğinden updateve Kalıcılık Bağlamı aynı varlığın iki temsilini tutamaz.
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)
Birleştirmek
Bundan kaçınmak için NonUniqueObjectException, mergeJPA tarafından sunulan EntityManagerve Hazırda Beklet tarafından devralınan yöntemi kullanmanız gerekir Session.
Açıklandığı gibi bu makalede , mergehiçbir varlık referansı Sebat Bağlamında bulundu varsa veritabanından yeni taraf anlık bir getirmektedir ve müstakil varlığın kopyalar devlet geçirilen mergeyöntemle.
mergeYöntem, bir tetikler MergeEventile kullanılan ve DefaultMergeEventListenerhazırda olay dinleyicisi.
mergeYöntemin nasıl çalıştığını görmek için Book, bir işlemde bir varlığa devam eden aşağıdaki örneği göz önünde bulundurun , ardından varlık ayrık durumdayken onu değiştirir ve ayrılmış varlığı mergebir sonraki Kalıcılık Bağlamına geçirir.
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);
});
Yukarıdaki test senaryosunu çalıştırırken, Hazırda Beklet aşağıdaki SQL deyimlerini yürüttü:
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
Tarafından döndürülen varlık referansının merge, mergeyönteme ilettiğimiz müstakil referanstan farklı olduğuna dikkat edin .
Şimdi, mergeayrılmış varlık durumunu kopyalarken JPA kullanmayı tercih etmenize rağmen , SELECTtoplu işleme görevini yürütürken fazlalık sorunlu olabilir.
Bu nedenle, updateo anda çalışan Kalıcılık Bağlamına eklenmiş bir varlık referansı olmadığından ve ayrılmış varlığın değiştirildiğinden emin olduğunuzda kullanmayı tercih etmelisiniz .
Bu konu hakkında daha fazla bilgi için bu makaleye göz atın .
Sonuç
Bir varlığı sürdürmek için JPA persistyöntemini kullanmanız gerekir . Müstakil varlık durumunu kopyalamak için mergetercih edilmelidir. updateYöntem toplu işlemler, sadece için yararlıdır. saveVe saveOrUpdatesadece rumuzlarıdırlar updateve muhtemelen tüm bunları kullanmamalısınız.
Bazı geliştiriciler save, varlık zaten yönetilse bile çağırır , ancak bu bir hatadır ve yönetilen varlıklar için UPDATE, kalıcılık bağlamında yıkama zamanında otomatik olarak işlenir.
Daha fazla ayrıntı için bu makaleye göz atın .