Hazırda bekletme geç yükleme uygulama tasarımı


87

Hibernate'i Spring çerçevesi ve onun bildirime dayalı işlem sınırlama yetenekleri (örneğin @Transactional ) ile birlikte kullanma eğilimindeyim .

Hepimizin bildiği gibi, hazırda bekletme , mümkün olduğunca müdahaleci olmayan ve şeffaf olmaya çalışır , ancak bu, ilişkileri uygularken biraz daha zorlayıcıdırlazy-loaded .


Farklı şeffaflık seviyelerine sahip bir dizi tasarım alternatifi görüyorum.

  1. İlişkileri tembel olmayan bir şekilde yapın (ör. fetchType=FetchType.EAGER)
    • Bu, tüm tembel yükleme fikrini geçersiz kılar ..
  2. Kullanarak koleksiyonları başlat Hibernate.initialize(proxyObj);
    • Bu, DAO'ya nispeten yüksek bağlantı anlamına gelir
    • İle bir arayüz tanımlayabilsek de initialize, diğer uygulamaların herhangi bir eşdeğer sağlaması garanti edilmez.
  3. Kalıcı Modelnesnelerin kendilerine işlem davranışı ekleyin ( dinamik proxy veya kullanarak @Transactional)
    • Dinamik proxy yaklaşımını denemedim, ancak @Transactional'ın kalıcı nesnelerin kendileri üzerinde çalışmasını hiç görmedim. Muhtemelen bu hazırda bekletme, birlikte olunacak bir proxy üzerinde işlemden kaynaklanmaktadır.
    • İşlemler gerçekten gerçekleşirken kontrol kaybı
  4. Hem tembel / tembel olmayan API sağlayın, örneğin loadData()veloadDataWithDeps()
    • Uygulamayı hangi rutini ne zaman kullanacağını bilmeye zorlar, yine sıkı bağlantı
    • Yöntem taşması, loadDataWithA()....,loadDataWithX()
  5. Bağımlılıklar için aramayı zorla, ör. Yalnızca byId()işlemleri sağlayarak
    • Örneğin, nesneye yönelik olmayan çok sayıda rutin gerektirir findZzzById(zid)ve getYyyIds(zid)bunun yerinez.getY()
    • İşlemler arasında büyük bir işlem ek yükü varsa, koleksiyondaki her nesneyi tek tek getirmek faydalı olabilir.
  6. Yalnızca DAO yerine @Transactional uygulamanın bir parçası olun
    • İç içe yerleştirilmiş işlemlerle ilgili olası hususlar
    • İşlem yönetimi için uyarlanmış rutinler gerektirir (örneğin, yeterince küçük)
    • Küçük programatik etki, ancak büyük işlemlerle sonuçlanabilir
  7. DAO'ya dinamik getirme profilleri sağlayın , ör.loadData(id, fetchProfile);
    • Uygulamalar hangi profili ne zaman kullanacaklarını bilmelidir
  8. AoP türü işlemler, örneğin işlemleri durdurma ve gerektiğinde işlemleri gerçekleştirme
    • Bayt kodu manipülasyonu veya proxy kullanımı gerektirir
    • İşlemler yapıldığında kontrol kaybı
    • Kara büyü, her zamanki gibi :)

Herhangi bir seçeneği kaçırdım mı?


lazy-loadedUygulama tasarımınızda ilişkilerin etkisini en aza indirmeye çalışırken tercih ettiğiniz yaklaşım hangisidir?

(Oh, ve WoT için üzgünüm )


2. ve 5. seçenek için örnek: m-hewedy.blogspot.ch/2010/03/…
Adrien Be

4. seçenek için bir örnek verebilir misiniz?
derecedc

Yanıtlar:


26

Hepimizin bildiği gibi, hazırda bekletme, mümkün olduğunca non-invaziv ve şeffaf olmaya çalışır.

İlk varsayımın yanlış olduğunu söyleyebilirim. Transaparent kalıcılık bir efsanedir, çünkü uygulama her zaman varlık yaşam döngüsüne ve yüklenen nesne grafiğinin boyutuna dikkat etmelidir.

Hazırda Bekletme'nin düşünceleri okuyamadığını unutmayın; bu nedenle, belirli bir işlem için belirli bir bağımlılık grubuna ihtiyacınız olduğunu biliyorsanız, niyetlerinizi bir şekilde Hazırda Bekletme'ye ifade etmeniz gerekir.

Bu bakış açısından, bu niyetleri açıkça ifade eden çözümler (yani 2, 4 ve 7) mantıklı görünüyor ve şeffaflık eksikliğinden muzdarip değil.


Elbette haklısın, mümkün olduğu kadar şeffaf sadece şimdiye kadar çalışıyor. Bunlar gittiğiniz bazı güzel seçimler.
Johan Sjöberg

IMHO: tamamen doğru cevap. Aslında bu bir efsanedir. BTW: Benim
oyum

7

Hangi soruna (tembellikten kaynaklanıyor) ima ettiğinizden emin değilim, ancak benim için en büyük acı, kendi uygulama önbelleklerimde oturum bağlamını kaybetmekten kaçınmaktır. Tipik durum:

  • nesne fooyüklenir ve bir haritaya konur;
  • başka bir iş parçacığı bu nesneyi haritadan alır ve çağırır foo.getBar()(daha önce hiç çağrılmamış ve tembel olarak değerlendirilen bir şey);
  • Boom!

Yani, bunu ele almak için bir takım kurallarımız var:

  • oturumları olabildiğince şeffaf bir şekilde sarın (örneğin, web uygulamaları OpenSessionInViewFilteriçin);
  • db oturum bağlama / çözme işleminin hiyerarşide yüksek bir yerde (sarmalanmış try/finally) yapıldığı iş parçacıkları / iş parçacığı havuzları için ortak API'ye sahip olur, böylece alt sınıflar bunun hakkında düşünmek zorunda kalmaz;
  • nesneleri iş parçacıkları arasında geçirirken, nesnelerin kendileri yerine kimlikleri iletin. Evre almak gerekirse nesneyi yükleyebilir;
  • nesneleri önbelleğe alırken, asla nesneleri değil kimliklerini önbelleğe almayın. Kimliği bildiğinizde nesneyi 2. düzey Hazırda Bekletme önbelleğinden yüklemek için DAO veya yönetici sınıfınızda soyut bir yönteme sahip olun. 2. seviye Hazırda Bekletme önbelleğinden nesneleri geri getirmenin maliyeti hala DB'ye gitmekten çok daha ucuzdur.

Bu, gördüğünüz gibi, aslında hiçbir yerde non-invaziv ve şeffaf değildir . Ancak, istekli yükleme için ödemem gereken fiyatla karşılaştırmak için maliyet hala katlanılabilir. İkincisiyle ilgili sorun, bazen bir varlık koleksiyonu bir yana, tek referanslı nesneyi yüklerken bile kelebek etkisine yol açmasıdır. Bellek tüketimi, CPU kullanımı ve en az bahsetmek için gecikme de çok daha kötü, bu yüzden bununla yaşayabilirim.


Cevabın için teşekkürler. Kaybı transparency, uygulamayı tembel nesnelerin yüklenmesini önemsemeye zorlamaktan kaynaklanmaktadır. Her şey hevesle getirilmişse, uygulama nesnelerin bir veritabanında saklanıp kalmadığından tamamen habersiz olabilir , çünkü Foo.getBar()her zaman başarılı olacaktır. > when passing objects between threads, pass IDs, evet, bu # 5'e karşılık gelir.
Johan Sjöberg

3

Çok yaygın bir model, bir web uygulaması oluşturuyorsanız OpenEntityManagerInViewFilter kullanmaktır .

Bir hizmet oluşturuyorsanız, TX'i DAO'lardan ziyade hizmetin genel yönteminde açardım, çünkü çoğu zaman bir yöntem birkaç varlığın alınması veya güncellenmesini gerektirir.

Bu, herhangi bir "Lazy Load istisnasını" çözecektir. Performans ayarı için daha gelişmiş bir şeye ihtiyacınız varsa, profilleri getirme yolu budur.


1
Ne demek istedi sanırım: Çok sık antipattern ... . OSIVTX'i hizmet düzeyinde açmayı kabul etmeme rağmen , ancak kullanımı hala bir anti-modeldir ve istisnalar veya performans düşüşüyle ​​zarif bir şekilde başa çıkamama gibi çok ciddi sorunlara yol açar. Özetlemek gerekirse: IMHO OSIV kolay giden bir çözümdür, ancak sadece oyuncak projeleri için iyidir.
G. Demecki
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.