MS Lesson10: JPA and EntityManagerFactory
JPA
1. Method name query
mes: findById(1L);
2. Native query
@Query(value = "SELECT COALESCE(SUM(p.scholarship), 0) FROM persons p", nativeQuery = true)
BigDecimal sumAllScholarshipsNative();
3. @Modifying ve @Transactional neye gore lazimdir?
@Modifying
@Transactional
@Query("UPDATE Person p SET p.scholarship = p.scholarship + :amount WHERE p.id = :id")
int increaseScholarship(@Param("id") Long id, @Param("amount") BigDecimal amount);
@Modifying olmasa spring bunu select kimi anlayir, ve ona gore exception atir. Springe deyirki bu sorgu data deyishdirir. Bu annotasiya olmasa Spring select rejimde ishleyecek.
@Transactional olmasa atomiklik ve commit ile tetbiq olunmur.
DB-de update/delete/insert transaction daxilinde olmalidir.
Hetta native query yazsaq bele yene bize bu annotasiyalar lazimdir:
@Modifying
@Transactional
@Query(value = "UPDATE persons SET scholarship = scholarship + :amount WHERE id = :id", nativeQuery = true)
int increaseScholarshipNative(@Param("id") Long id, @Param("amount") BigDecimal amount);
EntityManagerFactory və EntityManager
JPA / Hibernate dünyasında iki əsas oyunçu var:
- EntityManagerFactory – “zavod”
- EntityManager – “işçi”
1. Böyük şəkil: ApplicationContext → EntityManagerFactory → EntityManager → Connection → Database
Spring Boot tətbiqində axın təxmini belədir:
Yadda saxla:
- EntityManagerFactory – tətbiq boyu 1 dəfə yaradılır (ApplicationContext kimi).
- EntityManager – hər transaction / iş üçün ayrıca yaradılıb bağlanan “session” kimidir.
- Connection – Hikari hovuzundan götürülür, DB ilə TCP kanalıdır.
2. EntityManagerFactory nədir?
Bunu belə təsəvvür et:
EntityManagerFactory = Hibernate üçün “zavod” + metadata cache.
Server start olanda:
- JPA konfiqurasiyası oxunur (
spring.jpa.*,persistence-unitvə s.) - Bütün
@Entitysinifləri (Student,Coursevə s.) scan olunur. - Hər entity üçün:
- cədvəl adı
- sütunlar
- əlaqələr (OneToMany, ManyToOne və s.)
- ID strategiyası
- və s. metadata hazırlanır.
- Dialect (məs.
PostgreSQLDialect) seçilir. - Nəticədə 1 dənə EntityManagerFactory obyekt-i yaranır.
Logda bunu görürsən:
Bu obyekt:
- bahalıdır (çox iş görür)
- amma nadirdir (tətbiq boyu 1 dənə)
3. EntityManager nədir?
EntityManager = Hibernate Session = Entity-lərlə işləyən “işçi” obyekt.
Onun işi:
find(),persist(),merge(),remove()kimi əməliyyatlarla entity-lərlə işləmək- 1 transaction ərzində entity-ləri izləmək (dirty checking)
- lazy loading etmək
- cache / identity map saxlamaq (eyni entity-ni 2 dəfə DB-dən oxumamaq və s.)
Daha sadə:
- EntityManagerFactory = planları bilən zavod
- EntityManager = həmin plan əsasında real obyektlərlə işləyən ustalar (session-lar)
4. Spring Boot-da bunlar necə yaranır?
Spring Boot JPA starter (spring-boot-starter-data-jpa) sayəsində avtomatik:
DataSource(HikariCP)EntityManagerFactoryPlatformTransactionManager(JPA transaction manager)- JPA repository-lər üçün proxy-lər
5. Əməliyyat zamanı nə baş verir? – Diaqramla
Tutaq ki, bu kod var:
findById içində də:
5.1. Transaction olan ssenari (@Transactional service-də)
Daxildə baş verənlər (sadələşdirilmiş):
Burada bütün əməliyyatlar eyni EntityManager və eyni Connection ilə gedir.
5.2. Transaction OLMADAN, open-in-view=false
Tutaq ki, service-də heç @Transactional yoxdur, open-in-view də false-dur.
Bu halda:
Burada hər repository çağırışı öz kiçik EntityManager ömrünə sahib ola bilər.
6. “Bir əməliyyatda neçə EntityManager yaranır?” – Real sual
- Service-də
@Transactionalvarsa:- Adətən bir transaction = bir EntityManager = bir Connection (HTTP request-in həmin hissəsi üçün).
@Transactionalyoxdursa,open-in-view=falseisə:- Hər repository metodu üçün ayrıca qısa ömürlü EntityManager yarana bilər.
- Hər sorğu öz implicit / auto-commit transaction-u ilə işləyir.
Ən sağlam pattern:
Business əməliyyatlarını (məs. createStudent, transferMoney, placeOrder) service layer-də @Transactional ilə idarə etmək → 1 use-case = 1 transaction = 1 EntityManager.
7. EntityManagerFactory / EntityManager / Connection – kodla təsəvvür
Blogda göstərmək üçün belə bir pseudo-kod yerləşdirə bilərsən:
Real Spring-də bu kodu sən yazmırsan, Spring + Hibernate + Hikari birlikdə icra edir, amma məntiq budur.
8. Diaqram – blog üçün gözəl görünən forma
Blogda belə bir ASCII / şəkil diaqramı verə bilərsən:
Entity Manager-in hell etdiyi problemlerden biri:
package guru.springframework.cruddemo;
import guru.springframework.cruddemo.entity.Person;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootApplication
@RequiredArgsConstructor
public class CrudDemoApplication implements CommandLineRunner {
private final EntityManager entityManager;
public static void main(String[] args) {
SpringApplication.run(CrudDemoApplication.class, args);
}
@Override
@Transactional(readOnly = true)
public void run(String... args) throws Exception {
String nameContains = "a";
BigDecimal minScholarship = new BigDecimal("500");
BigDecimal maxScholarship = new BigDecimal("1500");
StringBuilder jpql = new StringBuilder("SELECT p FROM Person p WHERE 1=1");
Map<String, Object> params = new HashMap<>();
if (nameContains != null && !nameContains.isBlank()) {
jpql.append(" AND LOWER(p.name) LIKE LOWER(:name)");
params.put("name", "%" + nameContains + "%");
}
if (minScholarship != null) {
jpql.append(" AND p.scholarship >= :minScholarship");
params.put("minScholarship", minScholarship);
}
if (maxScholarship != null) {
jpql.append(" AND p.scholarship <= :maxScholarship");
params.put("maxScholarship", maxScholarship);
}
jpql.append(" ORDER BY p.createdAt DESC");
TypedQuery<Person> query = entityManager.createQuery(jpql.toString(), Person.class);
params.forEach(query::setParameter);
List<Person> people = query.setMaxResults(10).getResultList();
people.forEach(System.out::println);
}
}
Комментарии
Отправить комментарий