TL; DR
T findOne(ID id)
(nama di API lama) / Optional<T> findById(ID id)
(nama di API baru) bergantung pada EntityManager.find()
yang melakukan pemuatan entitas yang bersemangat .
T getOne(ID id)
bergantung pada EntityManager.getReference()
yang melakukan pemuatan entitas malas . Jadi untuk memastikan pemuatan entitas yang efektif, diperlukan metode untuk itu.
findOne()/findById()
benar-benar lebih jelas dan mudah digunakan daripada getOne()
.
Jadi dalam sangat sebagian besar kasus, mendukung findOne()/findById()
lebih getOne()
.
Perubahan API
Setidaknya dari 2.0
versi, Spring-Data-Jpa
dimodifikasi findOne()
.
Sebelumnya, itu didefinisikan dalam CrudRepository
antarmuka sebagai:
T findOne(ID primaryKey);
Sekarang, findOne()
metode tunggal yang akan Anda temukan CrudRepository
adalah yang didefinisikan dalam QueryByExampleExecutor
antarmuka sebagai:
<S extends T> Optional<S> findOne(Example<S> example);
Yang akhirnya diimplementasikan oleh SimpleJpaRepository
, implementasi standar CrudRepository
antarmuka.
Metode ini adalah kueri dengan pencarian contoh dan Anda tidak ingin itu sebagai pengganti.
Faktanya, metode dengan perilaku yang sama masih ada di API baru tetapi nama metode telah berubah.
Itu diubah namanya dari findOne()
menjadi findById()
di CrudRepository
antarmuka:
Optional<T> findById(ID id);
Sekarang mengembalikan sebuah Optional
. Yang tidak begitu buruk untuk dicegah NullPointerException
.
Jadi, pilihan sebenarnya sekarang antara Optional<T> findById(ID id)
dan T getOne(ID id)
.
Dua metode berbeda yang mengandalkan dua metode pengambilan EntityManager JPA yang berbeda
1) Optional<T> findById(ID id)
Javadoc menyatakan bahwa:
Mengambil entitas dengan idnya.
Ketika kita melihat implementasi, kita dapat melihat bahwa itu bergantung EntityManager.find()
untuk melakukan pengambilan:
public Optional<T> findById(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
Class<T> domainType = getDomainClass();
if (metadata == null) {
return Optional.ofNullable(em.find(domainType, id));
}
LockModeType type = metadata.getLockModeType();
Map<String, Object> hints = getQueryHints().withFetchGraphs(em).asMap();
return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));
}
Dan di sini em.find()
adalah sebuah EntityManager
metode dinyatakan sebagai:
public <T> T find(Class<T> entityClass, Object primaryKey,
Map<String, Object> properties);
Status javadoc-nya:
Temukan dengan kunci utama, menggunakan properti yang ditentukan
Jadi, mengambil entitas yang dimuat tampaknya diharapkan.
2) Sementara T getOne(ID id)
javadoc menyatakan (penekanan adalah milikku):
Mengembalikan referensi ke entitas dengan pengidentifikasi yang diberikan.
Faktanya, terminologi rujukan benar-benar papan dan JPA API tidak menentukan getOne()
metode apa pun .
Jadi hal terbaik yang harus dilakukan untuk memahami apa yang dilakukan pembungkus Spring adalah dengan melihat implementasinya:
@Override
public T getOne(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
return em.getReference(getDomainClass(), id);
}
Berikut em.getReference()
adalah EntityManager
metode yang dinyatakan sebagai:
public <T> T getReference(Class<T> entityClass,
Object primaryKey);
Dan untungnya, EntityManager
javadoc mendefinisikan dengan lebih baik niatnya (penekanan adalah milikku):
Dapatkan contoh, yang keadaannya mungkin diambil dengan malas . Jika instance yang diminta tidak ada dalam database, EntityNotFoundException dilemparkan ketika keadaan instance diakses pertama kali . (Runtime penyedia persistensi diizinkan untuk melempar EntityNotFoundException ketika getReference dipanggil.) Aplikasi tidak boleh berharap bahwa keadaan instance akan tersedia pada saat dilepas , kecuali itu diakses oleh aplikasi ketika manajer entitas terbuka.
Jadi, memohon getOne()
dapat mengembalikan entitas yang diambil malas.
Di sini, pengambilan malas tidak merujuk pada hubungan entitas tetapi entitas itu sendiri.
Ini berarti bahwa jika kita memanggil getOne()
dan kemudian konteks Persistence ditutup, entitas mungkin tidak pernah dimuat dan hasilnya benar-benar tidak dapat diprediksi.
Misalnya jika objek proxy serial, Anda bisa mendapatkan null
referensi sebagai hasil serial atau jika metode dipanggil pada objek proxy, pengecualian seperti LazyInitializationException
dilemparkan.
Jadi dalam situasi seperti ini, lemparan EntityNotFoundException
itu adalah alasan utama yang digunakan getOne()
untuk menangani sebuah instance yang tidak ada dalam database karena situasi kesalahan mungkin tidak pernah dilakukan ketika entitas tidak ada.
Bagaimanapun, untuk memastikan pemuatannya, Anda harus memanipulasi entitas saat sesi dibuka. Anda dapat melakukannya dengan menggunakan metode apa pun pada entitas.
Atau penggunaan alternatif yang lebih baik findById(ID id)
daripada.
Mengapa API begitu tidak jelas?
Untuk menyelesaikan, dua pertanyaan untuk pengembang Spring-Data-JPA:
mengapa tidak memiliki dokumentasi yang lebih jelas getOne()
? Entitas pemuatan malas sebenarnya bukan detail.
mengapa Anda perlu memperkenalkan getOne()
untuk membungkus EM.getReference()
?
Mengapa tidak hanya menempel metode dibungkus: getReference()
? Metode EM ini sangat khusus saat getOne()
menyampaikan pemrosesan yang sangat sederhana.