SOLR/ES/Lucene - full text search
Vector search - next thing
Brian: paginare N rezultate, apoi N/2 , N/4 ... dar intr-o singura tranzactie
Query-uri dinamice:
1. concat string-uri: WHERE 1+1" (ca apoi sa poti concatena alte conditii, if criteria)
2. Query DieSL: JpaQuery
- Diesel genereaza entitatile (ex. QMaterial)
3. CriteriaAPI
Planul de executie uraste "OR"
- face cache la planul construit anterior
- query diferit: alt plan
Index: ideal e sa ai distributie buna pe date (nu prea multe valori repetitive)
AskTom - (Oracle) - intrebari tuning etc
@Id
@GeneratedValue(strategy = _ )
- SEQUENCE: trebuie creata; la rollback tranzactie nu se poate recupera (da impresia ca e un rand sters in table)
INCREMENT BY 50: tragi din baza 50 id-uri odata
- IDENTITY = auto-increment; ceri de fiecare data din baza
- PK violation daca inserezi id-uri 'cunoscute'
- UUID - greu de ghicit, poate fi generat de client; dar urat
- TABLE
@Embedded pe un obiect din entity -> muti anumite attribute din clasa (coloane) pt a-i scurta marimea
@Entity to Domain Model - vezi notele
@Transactional pe metoda - nu poti face face try/catch pe query
- interzise tranzactiile manuale
Write behind: JPA amana scrierile pana inainte de commit (flush)- pt a insera/update in batch-uri
em.flush() - grabeste flush, dar nu comite; crapa de la erori
+ un select ar putea grabi flush
Carte: "Release it!"
Entitate gasita cu find pe o metoda @Transactional:
.set...() face update (auto-save)
alt .set nu face / nu se mai potriveste equals
em.detach(obj); // scoate din urmarire
em.clear(); // elimina din context toate entitatile (detach la tot), goleste 1st level cache al lui Hibernate
flush vs clear:
- flush scrie tot ce avea de scris; util: inainte sa chemi un PL/SQL, Trigger sau native query.
- goleste fara sa scrie nimic
@DynamicUpdate - modifica coloana din entitate doar daca chiar se modifica
1st level cache = transaction-scoped; find se uita in cache
2nd level cache = intre request-uri diferite (optional @Cacheble pe @Entity sau query hint)
- util: primul select ia din baza, al doilea select identic intr-un TTL=5 min ia din cache
Persistence context
@Cache pe entity class
em.merge(entity); // update fara auto-save, fara @Transactional, cand construiesti cu new entitatea Venita de la client (nu mai faci find)
Merge = suprascriere entitate veche
select parinte, copii si apoi update
cascade
- DETACH ~ detaseaza copiii odata cu parintele
- REFRESH ~ git reset
- MERGE - copiii se ins/upd/del
@Transactional cand doar citesti din BD: lazy init (entitatile-copii ca lista nu sunt dispo pt un framework gen Jackson)
@OneToMany(cascade = ALL, fetch = EAGER, orphanRemoval = true)
entitate parent.getChildren().remove(1) => UPDATE copil set parent null => cu orphanRemoval omoara copiii cu FK = null
( valabil la em.merge )
Cand un camp nu trebuie sa fie modificat pe un flux (ajuta cu merge side effects):
1) @Column(updatable = false) String createdBy; // eroare daca incerci sa modifici din cod
2) setCreatedBy - ignora/arunca eroare daca e deja setat campul
3) suprascrii cu valoarea care era initial in baza
Concurenta la modificare entitate:
Optimistic lock: te lasa sa scrii, cand salvezi iti da eroare daca cineva a salvat inaintea ta
@Version
private Long version; // sau LocalDateTime
// la em.merge(entity) se adauga o conditie suplimentara: AND version = 1 (cat era pe entity)
Pessimistic lock: pus lock in baza = intarzie a doua tranzactie pana comite prima
cu row lock: SELECT ... where version=7 FOR UPDATE [NO WAIT - la nivel de rand]
- face lock pe randurile returnate de SELECT
tx2 va astepta pana tx1 comite; = default in postgres/H2
adaugare coloane IN_EDIT_BY, IN_EDIT_SINCE cand materialul incepe sa fie editat de un user (lock pe linia din tabel)
Nu folosim synchronized in EJB
Monitorizare "connection acquisition time" = metrici - Grafana, Kibana, New Relic
@Transactional:
persist, flush nu duc la commitment daca apare exceptie in metoda tranzactata
- orice metoda chemata in thread-ul curent e parte din aceeasi tranzactie
- thread async: NU, si acopera exceptia; pt ca se pierde conexiunea JDBC care avea tranzactia pornita; nu merge nici daca pasezi EntityManager-ul de pe thread-ul gazda
Metoda @Transactional care cheama alta metoda @Transactional = e aceeasi tranzactie (parinte)
Propagation.REQUIRES_NEW ca sa fie distincta
TxType.REQUIRED = este default
throw checked exception intr-o metoda @Transactional nu impiedica commit-ul, doar unchecked (runtime) impiedica (!!!)
=> metoda @Transactional nu se recomanda cu throws! - faci try/catch/throw RuntimeException
@Transactional cu Propagation.REQUIRES_NEW pe o metoda-copil din acelasi serviciu = ca si cum nu are @Transactional
! nu se da API-call din @Transactional
Deadlock:
synchronized(x) din java + SELECT FOR UPDATE id=7 in parallel cu
SELECT FOR UPDATE id=7 + synchronized(x) din java
View materializat pe disc si actualizat periodic;
Rainbow brackets- plugin IntelliJ
DbUnit
Tuning tips:
- EXISTS (SELECT...) in loc de SELECT COUNT() sau id=(SELECT id...)
- Evita SELECT DISTINCT pe mai multe coloane = multe comparatii
- WHERE in loc de HAVING
- INNER JOIN ON <cond> in loc de WHERE<cond>
- LIMIT
- UNION ALL nu UNION (=DISTINCT)
- A UNION B in loc de WHERE... OR..
- GROUP BY in loc de OVER PARTITION BY
- tabele auxiliare
- IN si = in loc de != si <> si NOT IN
Niciun comentariu:
Trimiteți un comentariu