Hibernate Dərin Baxış
Hibernate, JPA spesifikasiyasının ən geniş istifadə edilən implementasiyalarından biridir (lakin JPA-dan əvvəl mövcud idi və daha aşağı səviyyəli imkanlar təqdim edir). Bu sənəd Spring Data JPA səviyyəsindən daha dərin Hibernate xüsusiyyətlərini izah edir.
Hibernate vs JPA
| Mövzu | JPA | Hibernate |
|---|---|---|
| Standart | Specification API | Implementation + əlavə extension-lar |
| Query | JPQL | HQL (JPQL super-set) |
| Criteria | Criteria API | Criteria + Hibernate-ə xas özelliklər |
| Cache strategiyaları | Ümumi interfeys | Ətraflı provider xüsusiyyətləri |
| NaturalId | Standarta daxil deyil | Dəstək var |
| Multi-Tenant | Məhdud | Daha çox pattern |
Əsas Arxitektura
| Termin | İzah |
|---|---|
| Session | EntityManager analoqu (stateful) |
| SessionFactory | Application-wide, thread-safe, heavyweight obyekt |
| Persistence Context | Managed entity-lərin dəqiq snapshot-u |
| Dirty Checking | Dəyişən sahələrin avtomatik aşkarlanması |
| Flush | Dəyişikliklərin SQL-ə çevrilib DB-yə göndərilməsi |
| Flush Mode | AUTO, COMMIT, MANUAL |
Session Yaratma (Standalone)
Koda bax
Configuration cfg = new Configuration().configure(); // hibernate.cfg.xml
ServiceRegistry registry = new StandardServiceRegistryBuilder()
.applySettings(cfg.getProperties()).build();
SessionFactory sf = cfg.buildSessionFactory(registry);
try(Session session = sf.openSession()){
Transaction tx = session.beginTransaction();
// iş
tx.commit();
}
Flush Davranışı
| Flush Mode | Nə Zaman Flush | İstifadə |
|---|---|---|
| AUTO | Sorğu əvvəlində / transaction sonunda | Default |
| COMMIT | Yalnız commit zamanı | Performans artımı, lakin stale read riski |
| MANUAL | Əl ilə flush() çağırışı | Xüsusi bulk əməliyyatlar |
Dirty Checking Mexanizmi
Hibernate entity snapshot saxlayır. Getter/setter ilə dəyişən sahələr commit zamanı müqayisə edilir. Final/primitive dəyişmələri düzgün dizayn et. @DynamicUpdate əlavə sütun sayını azalda bilər.
Entity Mapping Genişlənmələri
| Hibernate Annotasiyası | Məqsəd |
|---|---|
@Type | Custom tip map |
@NaturalId | Təbii unikal açar |
@Formula | Virtual sütun (subquery expression) |
@CreationTimestamp | Avtomatik timestamp |
@UpdateTimestamp | Update zamanı timestamp |
@BatchSize | Batch loading hint |
Koda bax
@Entity
@BatchSize(size = 20)
class Product {
@Id @GeneratedValue Long id;
@NaturalId
@Column(unique = true, nullable = false)
private String sku;
@Formula("(select avg(r.rating) from review r where r.product_id = id)")
private Double avgRating;
}
İnheritence Strategiyaları
| Strategiya | Annotasiya | Üstünlük | Çatışmazlıq |
|---|---|---|---|
| Single Table | @Inheritance(SINGLE_TABLE) | Performans, az join | Sütun israfı, nullable-lar |
| Joined | @Inheritance(JOINED) | Normalizasiya | Join overhead |
| Table Per Class | @Inheritance(TABLE_PER_CLASS) | Ayrı cədvəllər | Union sorğuları bahalı |
Koleksiya Tipləri
| Tip | Davranış |
|---|---|
| List | Order saxlanır (ORDER BY / @OrderColumn) |
| Set | Unikal elementlər |
| Map | Key-value (join table ilə) |
| SortedSet/SortedMap | Comparable tələb |
Fetch Strategiyaları (Hibernate Əlavələri)
| Mexanizm | İzah |
|---|---|
@BatchSize | Eyni tip LAZY obyektləri IN (...) ilə yükləyir |
| SUBSELECT | İlk sorğudan sonra qalanları subselect ilə çəkir |
| SECOND LEVEL CACHE | LAZY obyekt DB əvəzinə cache-dən |
İkinci Səviyyə Cache (2LC)
| Layer | İzah |
|---|---|
| 1-ci (Session) | Transaction scope |
| 2-ci | SessionFactory scope |
| Query Cache | Sorğunun nəticə ID-lərini saxlayır |
Cache Strategiyaları
| Strategiya | Məqsəd |
|---|---|
| READ_ONLY | Dəyişməyən data (lookup tables) |
| READ_WRITE | Konsistent yazma/oxuma |
| NONSTRICT_READ_WRITE | Zəif konsistensiya, daha sürətli |
| TRANSACTIONAL | JTA səviyyəli sərt konsistensiya |
Koda bax
<!-- hibernate.cfg.xml -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.jcache.JCacheRegionFactory</property>
<property name="hibernate.javax.cache.provider">org.ehcache.jsr107.EhcacheCachingProvider</property>
Query API-ları
| API | Üstünlük |
|---|---|
| HQL | Entity yönümlü |
| Criteria | Dinamik tip təhlükəsiz |
| Native SQL | Performans kritik / xüsusi funksiyalar |
| Statik Named Query | Reuse + startup yoxlanışı |
Koda bax
List<Product> list = session.createQuery("from Product p where p.price > :min", Product.class)
.setParameter("min", 100)
.setMaxResults(50)
.list();
Scrollable Results / Streaming
Böyük dataset-lərdə memory istifadəsini reduce etmək üçün.
Koda bax
ScrollableResults results = session.createQuery("from Order", Order.class)
.setFetchSize(50)
.scroll(ScrollMode.FORWARD_ONLY);
while(results.next()){
Order o = (Order) results.get()[0];
// prosess
if(results.getRowNumber() % 50 == 0){
session.clear(); // memory təmizlə
}
}
Batch Operations
| Texnika | İzah |
|---|---|
| JDBC batch | hibernate.jdbc.batch_size |
| StatelessSession | 1-ci səviyyə cache olmadan sürətli bulk |
| Session#clear | Memory blow-up qarşısı |
Koda bax
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for(int i=0;i<10_000;i++){
User u = new User();
u.setUsername("u"+i);
session.persist(u);
if(i % 50 == 0){
session.flush();
session.clear();
}
}
tx.commit();
Interceptor və Event Sistemi
| Mexanizm | Məqsəd |
|---|---|
| Interceptor | Lifecycle hook-lar (onSave, onDelete) |
| EventListener | Daha granular event-lər |
| EntityListener | JPA səviyyəli (@PrePersist ...) |
Koda bax
public class AuditInterceptor extends EmptyInterceptor {
@Override
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
Object[] previousState, String[] propertyNames, Type[] types) {
if(entity instanceof Auditable a){
a.setUpdatedAt(Instant.now());
}
return false;
}
}
Natural ID Lookup
Koda bax
Product p = session.byNaturalId(Product.class)
.using("sku", "ABC-123")
.load();
Multi-Tenancy Yanaşmaları
| Model | İzah |
|---|---|
| Separate DB | Hər tenant üçün ayrıca DB |
| Separate Schema | Eyni DB, fərqli schema |
| Discriminator Column | Tək cədvəl, tenant_id sütunu |
Discriminator modeli sadə, lakin data izoləsi zəif; ayrı DB modeli güclü, amma əməliyyat yükü çox.
Locking Strategiyaları
| Strategiya | Annotasiya | İstifadə |
|---|---|---|
| Optimistic | @Version | Konflikt az |
| Pessimistic | LockMode.PESSIMISTIC_WRITE | Yüksək yarış |
| Optimistic Force Increment | LockMode.OPTIMISTIC_FORCE_INCREMENT | Versiya artırma məcburi |
Koda bax
Order o = session.find(Order.class, id, LockMode.PESSIMISTIC_WRITE);
SQL Output Tənzimləmə
| Parametr | Effekti |
|---|---|
| hibernate.show_sql | Konsolda SQL |
| hibernate.format_sql | Oxunaqlı format |
| hibernate.highlight_sql | Rəngli (Hibernate 6) |
| hibernate.generate_statistics | Metriklər və log |
Performance Check List
- LAZY default saxla (EAGER-i azaldır)
- Fetch join + limit (cartesian explosion olmasın)
- Batch size (
hibernate.default_batch_fetch_size = 16/32) - İkinci səviyyə cache yalnız read-most üçün
- Hər 50-100 entity-də
flush/clearbulk zamanı - Projections: DTO (entity tam yükləmək əvəzinə)
- StatelessSession bulk insert
Tipik Anti-Patternlər
| Problem | Nəticə |
|---|---|
| Açıq Session UI (OSIV) sui-istifadə | Gec DB çağırışları, sürpriz sorğular |
| EAGER chain-lər | Şişmiş SELECT, N+1 zənciri |
| Hər sorğuda yeni SessionFactory | Startup cost + memory |
| Çox böyük bir transaction | Lock müddətinin artması |
| Random flush çağırışları | Gözlənilməz performans |
Sual-Cavab
| Sual | Cavab |
|---|---|
| JPA-dan niyə aşağı səviyyəyə enim? | Xüsusi optimizasiya / extension ehtiyacı |
| StatelessSession nə verir? | 1-ci səviyyə cache/dirty checking yoxdur → sürət |
| Query cache nə saxlayır? | ID siyahısı (entity-lər ayrıca 2LC-dən yüklənir) |
| NaturalId üstünlüyü? | Alternativ unikal açar ilə tez lookup |
flush() nə edir? | Change Set → SQL generation & execution |
Ən Yaxşı Təcrübələr
- SessionFactory-ni application lifecycle boyu reuse et
- Monitoring:
generate_statistics=trueilə lokal analiz → prod-da metric exporter istifadə et - Domain modelini aggregate sərhədləri ilə dizayn et (lazımsız uzun obyekt qrafı yükləmə)
- Custom tip üçün
AttributeConvertervə ya@Typeistifadə et - Sorğu sayı və ölçüsünü profil et (p95/p99 latency)
Növbəti Addım
Hibernate biliklərini möhkəmləndirmək üçün: spring/jpa sənədini yenidən nəzərdən keçir və DB dizayn optimallaşdırması üçün database/indeksler bölməsinə bax.