Lehet, hogy nem jól értek valamit.
Van 2 alkalmazás szerver. Nincs az Entity cache szinkronban.
Amikor kiíratom az SQL-t amit optimistic lock esetén végrehajt, egy ilyesmit látok: update version=?version+1 where version=?version and id=?id; Ez alapján úgy gondolnám, hogy nem lehet 2 írás ugyanazon a rekordon. Vagy mégis? Úgy tűnik mintha ennek ellenére 2x íródna nagyon ritkán ugyanaz a rekord, nem dob Exception-t.
- 1059 megtekintés
Hozzászólások
Az optimistic lock lényege az, hogy nem az adatbázis dolga az, hogy ne legyen két írás, ami egy sort érint, hanem azt megoldja a környezete, nincs tranzakció az adatbázisban... forráskódrészleted van amúgy?
- A hozzászóláshoz be kell jelentkezni
nem, az optimistic lock egy elv, ahol a felteves az, hogy nem fog utkozni az iras, es ezert erre az esetre optimalizalunk. vagyis az utkozes lesz draga, nem a 'nem-utkozes'.
sql eseten a transaction isolation-t kellene megnezni, ha ilyen gebasz van. pl. serializable eseten frankon pessimistic locking-al fogja sorositani az optimistic locking-ot megvalosito rendszert, kinyirva a teljesitmeny-nyereseget.
alapvetoen optimistic locking-hoz a document store idealis, nem a sql.
- A hozzászóláshoz be kell jelentkezni
nem, az optimistic lock egy elv, ahol a felteves az, hogy nem fog utkozni az iras, es ezert erre az esetre optimalizalunk. vagyis az utkozes lesz draga, nem a 'nem-utkozes'.
Ezt írtam én is, nem az adatbázis dolga, hanem a környezete oldja meg, hogy általánosságban ne legyen két írás egyidőben ugyanarra a rekordra, ha pedig van, akkor egy atomikusan kezelt - általában version nevű - mező várt vagy nem várt értékéből lehet kideríteni, hogy más is írt-e közben.
sql eseten a transaction isolation-t kellene megnezni, ha ilyen gebasz van. pl. serializable eseten frankon pessimistic locking-al fogja sorositani az optimistic locking-ot megvalosito rendszert, kinyirva a teljesitmeny-nyereseget.
Ennek semmi értelme.
alapvetoen optimistic locking-hoz a document store idealis, nem a sql.
Ez meg faszság.
- A hozzászóláshoz be kell jelentkezni
van ertelmes hozzaszolasod is? esetleg megosztod velunk ehelyett az utszeli stilus helyett?
- A hozzászóláshoz be kell jelentkezni
Volt értelmes hozzászólásom, mindössze korrigáltam azt, amit válaszoltál rá.
- A hozzászóláshoz be kell jelentkezni
szoval nem. legyszives ne trollkodd ossze masoknak fontos forumot, ha nincs erdemi mondandod.
- A hozzászóláshoz be kell jelentkezni
Nem trollkodtam, korrigáltam a hibás állításaidat. Bárki hozzászólására, aki beírja, hogy optimistic lock-hoz document store az ideális és nem az SQL, arra azt fogom mondani, hogy faszság. És nem csak én.
- A hozzászóláshoz be kell jelentkezni
tovabbra sem erveltel, csak ismetled, amit eddig irtal. Miert lenne sql idealis optimistic locking-hoz? a tobbtucat tablaba szejjelszort adathalmazzal, vs. 1 document? kb. nincs olyan eset, amikor a sql jobb megoldas lenne, csak tipikusan legtobb ember hideg medencebe bemaszas feeling-et kap, amikor nosql-el kell dolgoznia 20 ev sql utan.
en ugrottam, es nem bantam meg. azota utalom a sql-t, csak sajnos gyakran kenytelen vagyok hasznalni, mert a team is fontos.
- A hozzászóláshoz be kell jelentkezni
Miert lenne sql idealis optimistic locking-hoz?
Mert az optimistic lock egy technológia agnosztikus dolog.
Miert lenne sql idealis optimistic locking-hoz? a tobbtucat tablaba szejjelszort adathalmazzal, vs. 1 document?
Ez most ismét egy MongoDB vs fasz-se-tudja összehasonlítás? Kb. mindegyik RDBMS tud flexible document alapú sémát.
kb. nincs olyan eset, amikor a sql jobb megoldas lenne, csak tipikusan legtobb ember hideg medencebe bemaszas feeling-et kap, amikor nosql-el kell dolgoznia 20 ev sql utan.
Na, így se hülyézték még le például a Spotify mérnökeit, pedig eléggé sok mindenre használnak PostgreSQL adatbázist. Meg még egy csomó egyéb cég is, akik nem ragadtak le ott, hogy a MongoDB mindenre megoldás.
en ugrottam, es nem bantam meg. azota utalom a sql-t, csak sajnos gyakran kenytelen vagyok hasznalni, mert a team is fontos.
Szerintem neked az a fő bajod, hogy nem ismered a lehetőségeket, illetve soha nem vetted a fáradságot, hogy rendesen megtanulj valamit.
- A hozzászóláshoz be kell jelentkezni
hagyd, nagyon kemeny a srac :D
- A hozzászóláshoz be kell jelentkezni
Ami még fontos, hogy Oracle adatbázis és amikor ütközés van akkor a BatchUpdate-ra panaszkodik, hogy 1-et kellett volna visszaadnia a update-nek, de 0-át adott vissza.
Elég bonyolult a forráskód. Nem is mondanám tiszta kódnak. Inkább leírom a működést.
Van egy időzítő, ami időnként ráfut. Ez mivel nincs nagyon szinkronizálva (nem quartz-ot használ), így ráfuthat ugyanaz a gép is mégegyszer a feladatra, ha az előző nem fejezeződött be időre és a másik gép is.
Egy rest híváson keresztül kiveszi az aktuális max. sorszámot egy másik rendszerből, majd elkezdi feldolgozni x darabonként ezt. Külön tranzakciót nyit TransactionAttribute(REQUIRES_NEW)-al, lekéri az utoljára feldolgozott csomagszámot egy táblából (ezen van az optimistic lock). Elkezdi berakni egy táblába ezeket a csomagokat, hogy majd lekéri. Majd a végén beállítja az utoljára feldolgozott csomagszámot az entitáson és flush-t nyom rá. Ilyenkor ha optimistic lock van sokszor dobódik is. Majd visszatér a hívó metódushoz, ami az előző új tranzakción kívül van a berakott rekordok azonosítójival és bedobálja egy queba, későbbi feldolgozásra.
Itt időnként keletkeznek duplikált rekordok, ugyanazzal a csomagszámmal (ahova a csomagszámokat rekordonként berakta). Ha az optimistic lock miatt elbukna a program, akkor visszagörgetné a beíllesztett rekordokat is, ám úgy tűnik ritkán, de nem teszi.
A program úgy látom nem arra lett készítve, hogy több alkalmazásszerveren dolgozzon és nem ekkora mennyiségű adat feldolgozására. Most csak a mókolás a megengedett. Nem szabad túl sok fejlesztést beleölni.
- A hozzászóláshoz be kell jelentkezni
Ha nincs sok ezer tranzakció másodpercenként, akkor szerintem teljesen értelmetlen erre az optimistic lock használata... szerintem.
- A hozzászóláshoz be kell jelentkezni
Te mit használnál, hogy ne legyen ütközés? Sajnos vannak olyan időszakok, amikor több ezer is lehet másodpercenként.
- A hozzászóláshoz be kell jelentkezni
Ezt ennyiből nem lehet megállapítani, forráskódot, működésmódot, üzleti igényt és mindent is látni kellene ehhez.
- A hozzászóláshoz be kell jelentkezni
A quartz egy masszivan tulbonyolitott rendszer ahhoz kepest, amire tipikusan hasznaljak - tisztelet a kivetelnek, de semmit se lattam, amit a spring @schedule es a schedlock ne oldott volna meg tizedannyi komplexitasbol.
Abbol, amit irtal, azt tudom javasolni, vizsgald meg kozelebbrol, hogy mukodik az optimistic lock exception-t kezelo kod. hasonlot ugyanis lattam mar, ott az volt a gebasz, hogy a DBMS nem mindig ugyanazt a hibat adta, es a java + spring addig transformalgatta az exception-oket, hogy nem OptimisticLockingException lett a vegen, hanem valami egyeb.
A transaction isolation-t erdemes meg megnezni - esetfuggo, de a REPEATABLE_READ ugye egy tranzakcion belul ugyanazt adja vissza akkor is, ha a DB-ben mar megvaltozott a version... aztan meg commit-nal dob egy hatast. READ_COMMITTED a celszeru.
A program úgy látom nem arra lett készítve, hogy több alkalmazásszerveren dolgozzon és nem ekkora mennyiségű adat feldolgozására. Most csak a mókolás a megengedett. Nem szabad túl sok fejlesztést beleölni.
Nem bantani akarlak, de ennek alapjan en nem toltenek tobb idot azon a helyen a feltetlen szuksegesnel. Celszeru korbenezni, ennel csak jobbat fogsz talalni.
- A hozzászóláshoz be kell jelentkezni
A transaction isolation-t erdemes meg megnezni - esetfuggo, de a REPEATABLE_READ ugye egy tranzakcion belul ugyanazt adja vissza akkor is, ha a DB-ben mar megvaltozott a version... aztan meg commit-nal dob egy hatast. READ_COMMITTED a celszeru.
Ahogy már írtam, az optimistic lock lényege az, hogy _nincs_ adatbázis oldali tranzakció, tehát izoláció sincs. Semmi értelme optimistic lock használatának akkor, ha amúgy is van tranzakció és izoláció az adatbázis műveletre.
- A hozzászóláshoz be kell jelentkezni
dehogynem! hiba eseten hogyan rollback-elsz? mikor az adatmodell 50 tabla, es a 20. tabla update utan van utkozes, vagy barmi huba, azt hogy oldod fel?
- A hozzászóláshoz be kell jelentkezni
Pont azt magyarázza, hogy amikor optimistic lock-ról beszélünk, akkor kikerüljük az adatbáziskezelő által biztosított locking mechanizmust, és egy "parasztlock"-ot csinálunk, amely
el fog szállni, ha közben valaki más is módosította azt a táblát, ahhoz képest, amit mi korábban láttunk. Ezután a folyamatnak kell biztosítania, hogy ezzel a művelettel valami történjen,
a legegyszerűbb az, hogy értesítjük a felhasználót, hogy bocsi, valaki már módosította a rekordot menet közben, küldjed be újra.
- A hozzászóláshoz be kell jelentkezni
tovabbra se magyaraztad meg, hogy ha 50 tablas az adatmodelled (mert sql ekkora fos), akkor a 20. tabla utan fellepo hibat hogyan gorgeted vissza *massziv* extra kezi admin + ezzel jaro komplexitas nelkul.
hint: sehogy
- A hozzászóláshoz be kell jelentkezni
tovabbra se magyaraztad meg, hogy ha 50 tablas az adatmodelled (mert sql ekkora fos), akkor a 20. tabla utan fellepo hibat hogyan gorgeted vissza *massziv* extra kezi admin + ezzel jaro komplexitas nelkul.
Egy darab rollback használatával. Semmi komplexitás nincs benne.
hint: sehogy
:D
- A hozzászóláshoz be kell jelentkezni
BEGIN TRAN;
-- do stupid shit here
ROLLBACK TRAN;
Thanks for coming to my TED talk.
- A hozzászóláshoz be kell jelentkezni
dehogynem! hiba eseten hogyan rollback-elsz?
SAGA pattern használatával, ez az ún. compensating transaction.
mikor az adatmodell 50 tabla, es a 20. tabla update utan van utkozes, vagy barmi huba, azt hogy oldod fel?
Ha nem tudok SAGA pattern alapján visszaállni, akkor nem használok optimistic lock-ot, mert semmi értelme ilyen esetben. Ha 20 táblát kell egyszerre módosítani, egy tranzakcióban, ráadásul READ_COMMITTED izolációval, egyben visszavonva a 20 tábla módosításait, akkor ott teljesen értelmetlen bármilyen optimistic lock használata, mert az adatbázis motor menedzseli a teljes tranzakciót, dugig tele van a tranzakció írásra és olvasásra zárolt sorokkal és táblákkal.
- A hozzászóláshoz be kell jelentkezni
Ezzel akkora extra komplexitas krealsz mint kodban, mint DB-ben, mint design-ban, ami tobb tizezer LoC-ra fog rugni. Vs. egy egyszeru document store kb. 5 sorban megold, mert:
- a schema a kodod modellje
- a de/ser -t ingyen kapod
- a document 1 object
- document optimistic lock-ot ingyen kapod
- az 1 document operation ACID
- A hozzászóláshoz be kell jelentkezni
Na, ismét egy MongoDB vs fasz-se-tudja összehasonlítás. Amúgy ezeket tudja egy tetszőleges mai RDBMS is...
- az 1 document operation ACID
Ez oximoron, az ACID több document-re értendő, a MongoDB ACID 4.0 óta van, amióta össze lehet fogni egy tranzakcióba több document-et, illetve 4.2 óta van shared ACID, amikor nem kell egy shard-ban lennie mindannak, amit egy tranzakcióban akarok kezelni.
Neked alapvető tudáshiányod van adatbázis terminológiában (is).
- A hozzászóláshoz be kell jelentkezni
- a schema a kodod modellje
Tokre nem minden esetben, noSQL-je valogatja sot akar noSQL serveren beluli indexenkent lehet kulonbozo
- a de/ser -t ingyen kapod
Mar amikor :D
- document optimistic lock-ot ingyen kapod
Na persze, biztos ha nagyon optimistak vagyunk :D Oszt a distributed systemekkel mi van, ahol mondjuk egy kuldo akar 4-5 fogadora is kuldi az adatot amit mindegyik le is rak a backend storage-ba (aminek majd lesz egy deduplikacios processze ami neha lefut)
- az 1 document operation ACID
Van olyan is, de amugy egy lofaszt altalanosithatunk :D
- A hozzászóláshoz be kell jelentkezni
mint kodban, mint DB-ben, mint design-ban
[off]
A szó, amit keresel: mind
[/off]
- A hozzászóláshoz be kell jelentkezni
Egyébként nem Springes az alkalmazás.
- A hozzászóláshoz be kell jelentkezni
Nagyjából stimmt, de itt vannak pontatlanságok.
Az "Optimistic Lock", vagy a nekem jobban tetsző nevén az "Optimistic Concurrency Control" egy párhuzamossági modell, amiben "lock" nem nagyon van a hagyományos értelemben.
Hogy ez hol valósul meg, szinte lényegtelen az elv szempontjából. Lehet az adatbázis dolga, lehet egy java framework dolga, vagy lekódolhatjuk mi is, sokféleképpen realizálható.
Megvalósulhat Postgres vagy Oracle alatt két "Repeatable read" tranzakció között, ami ugyanazon sort próbálja modositani, amit egyszer kiolvasott a "SELECT" paranccsal ami transparensen rögzíti a sor verzióját, majd az UPDATE segítségével később megpróbálja átirni - de mivel az izolációs szinte az elöbb emlitett "repeatable read" igy az egyik tranzakciót nem tudjuk committal lezárni (ERROR: could not serialize access due to concurrent update). MySQL alatti a Repeatable read más, ott pesszimista lock van pl.
Ugyanez megvalósulhat pl a Hibernate Version annotációval (adatbáyisban READ COMMITTED izolacios szint), ahol ugyanez az elv, csak egy explicit "version" oszlop van rá. A hibernate fogja ezt a verziot nyilvantartani, hogy mi volt az, amit kiolvasott (666), es ott a tranzakcio rollbackelve lesz, ha az "UPDATE xyz SET version = 667 WHERE version = 666" parancs 0 frissített sort ad vissza, (hiszen egy másik tranzakcio már frissítette ezt a sort). Ez az eset a téma indito problémája.
Illetve ugyanez megvalósulhat noSQL környezetben (polygot SQL + noSQL, stb... stb...) lekódolva, SAGA pattern, meg tudomisén mivel.
A pesszimista lock használata esetén nem kell felkészülni (nagyon) az ütközés esetére, hiszen ezek a tranzakciók majd sorban egymás után fognak lebonyolódni. (feltéve persze ha nem lesz deadlock - minden tranzakció ugyanabban a sorrendben foglalják le az erőforrást és oldják fel, stb stb stb)
Az optimista lock esetén pedig fel kell (kéne) készülni az ütközés lehetőségére, hiszen itt optimistán nincs lock, csak egy hibajelzés ha van ütközés. Megvalósitható mondjuk pl egy retry mechanismussal, ami megkísérli az egész db update folyamatot újra legelőről.
- A hozzászóláshoz be kell jelentkezni
Optimistic locknál azt kellene látnod, hogy az update-nél a verzió is benne van (ahol a többi mező update is).
Ez neked külön update-ben van? update version=?version+1 where version=?version and id=?id vagy csak lehagytad a többi mezőt?
Ha ugyanabban az update-ben van, akkor csak az egyik alkalmazás szerver fog tudni update-elni.
Esetleg még az is egy kérdés lehet, hogy milyen tranzakció izolációs szint van beállítva.
- A hozzászóláshoz be kell jelentkezni
Bocs. Igen. Az update tartalmaz minden mezőt. + a version felülírás sem így van: version+1, hanem version=?. Azaz a java-ból jön az új értéke.
Az izolációs szintet próbáltam lekérni, de nincs jogom hozzá :)
- A hozzászóláshoz be kell jelentkezni
Ez neked külön update-ben van? update version=?version+1 where version=?version and id=?id vagy csak lehagytad a többi mezőt? Ha ugyanabban az update-ben van, akkor csak az egyik alkalmazás szerver fog tudni update-elni.
Nekem amúgy az a gyanús, hogy olyan helyen és módon van használva az optimistic lock, ahol annak semmi értelmes szerepe nincs és így nyilván nem működik.
--
Tipikus (mondhatni tankönyvi) optimistic lock use-case az, hogy van egy balance(id, value, version) táblám. Meg kell nézzem, hogy van-e 100 pénze az illetőnek, ha van, le kell vonnom 100 pénzt az egyenlegből és vissza kell írnom, mindezt tranzakció nélkül.
Ilyenkor az történik, hogy van egy (123456789, 120, 0) értékem, lefut egy `SELECT * FROM balance WHERE id=123456789;`, ebből megkapom, hogy van 120 pénz és 0 a version, tehát beírhatom, hogy az új egyenleg 20 pénz. Lefuttatok egy `UPDATE balance SET value=20, version=1 WHERE id=123456789 AND version=0;` utasítást, ami csak akkor fog lefutni, ha a version értéke 0. Ha közben egy másik szálon, másik szerveren, másik programból ugyanerre a sorra valaki más levont pénzt (mondjuk 50 pénzt), akkor ez az UPDATE nem fog változtatást okozni, mert a version értéke már 1. A programom észre kell vegye, hogy nem futott le üzemszerűen az UPDATE, szóval újra kell futnia, ekkor már azt kapja, hogy (123456789, 70, 1) az értéke a sornak és nincs már 100 pénz az egyenlegen. Az adatbázisból tipikusan nem jön vissza exception, a futó programnak kell tudnia, hogy mikor kell megismételni a futást.
- A hozzászóláshoz be kell jelentkezni
Lehet én írtam félreérthetően, de pont a példádban szereplő hasonló eset forog fent itt is. Addig nem rakhatok el egy csomagot, amíg nem tudom, hogy el van-e már rakva az a csomag. Ez pedig abból derül ki, hogy melyik csomagnál tartott az előző futás.
Ebből a szempontból itt felesleges is lenne a párhuzamosan fusson több gépen. De mivel több időzítő is van több feladatra, így egy gép nem bírná el. Gondolom ezért raktak be több gépet és ezért is próbálkoztak optimistic lock-al. Ami megint csak nem pont a legjobb, mert nagy terhelésnél akár 3-4 szál is futhat egyszerre amelyik ezzel foglalkozik, majd a végén csak egy hajtódik végre, majd a többit eldobja. De mint látjuk, idpnként nem dobja el sem és emiatt duplikált csomagok keletkeznek.
Tehát az lenne az ideális eset ha pl. lenne egy DB-ben állapotot kezelő Quartz, ami nem engedné ráfuttatni ugyanazt az időzítőt még egyszer amíg a ugyanabból az időzítőből valamelyik fut. Viszont ekkora átírást most nem tudnak bevállalni.
Egyébként tesztekkel nem sikerült még előidéznünk, hogy nálunk duplikálódjón egy csomag. Mindig Optimistic lock keletkezett.
- A hozzászóláshoz be kell jelentkezni
Szerintem itt az alapvető probléma az, hogy több alkalmazásszerveren fut a motyó és nincs szinkronban az entity cache... de ez csak tipp.
Hozzátenném, hogy nem értem az optimistic lock hasznosságát ebben az esetben, lehetne sima sor szintű lock, a meglévő tranzakció részeként, adatbázis által kezelve és minden problémád megoldódna. Mi volt az ötlet alapja, hogy erre az optimistic lock a legjobb megoldás?
- A hozzászóláshoz be kell jelentkezni
Azt, hogy mi volt az ötlet alapja - nem tudom. Nem én írtam a programot. :)
A pesszimista zároláson már én is gondolkodtam. Csak ott nem tudom milyen egyéb gondok jöhetnek még elő a mostani kódon. Ezeket még át kell gondolnom. Nem akarok egy hiba cunnamit elindítani.
- A hozzászóláshoz be kell jelentkezni
Ezért szokták inkább inserttel csinálni az update-et úgy, hogy a version unique. Akkor már lesz version=1 rekord és az insert elfekszik a második esetben.
- A hozzászóláshoz be kell jelentkezni
Ezért szokták inkább inserttel csinálni az update-et úgy, hogy a version unique. Akkor már lesz version=1 rekord és az insert elfekszik a második esetben.
JPA tipikusan UPDATE műveletet hajt végre, abból is kiderül egyértelműen, hogy változott-e a version.
- A hozzászóláshoz be kell jelentkezni
Update az tulképpen pessimistic lock-ot jelent, nem?
Gábriel Ákos
- A hozzászóláshoz be kell jelentkezni
Nem, nincs rajta semmilyen lock. Ha egy másik folyamat közben lefuttatott egy UPDATE hívást, akkor az enyém nem fog lefutni, mert nincs már meg a WHERE feltételben az a version érték, amit figyelek.
Tehát van egy version=0 értékem, akkor beolvas két process egy azonos sort, majd lefuttatná ezt a két UPDATE-et:
UPDATE balance SET value=20, version=1 WHERE id=123456789 AND version=0;
UPDATE balance SET value=80, version=1 WHERE id=123456789 AND version=0;
Amelyik előbb fut, az atomikusan átírja a version értékét és a második UPDATE nem fog módosítani, mert nincs már version=0, mindegy, hogy melyik fut le előbb. Az adatbázis saját működésén kívül nincs lock a rendszerben, nem kell a két process számára mutex-et kezelni az adatbázisban, hogy ki más olvas és módosít időben átlapolt tranzakcióban azonos sorokat.
Az optimistic lock nem egy silver bullet, ahogy a normál tranzakció se az ördögtől való.
- A hozzászóláshoz be kell jelentkezni
Egyetértek.
Az a row level lock amit ilyenkor a pg odatesz az "architektúrális szempontból" nem számít, "nem én raktam oda".
Gábriel Ákos
- A hozzászóláshoz be kell jelentkezni
Nézzük meg!
https://github.com/hibernate/hibernate-orm/search?q=OptimisticEntityLoc…
A Hibernate így csinálja és itt úgy látom csak a version mezőjét nézi:
https://github.com/hibernate/hibernate-orm/blob/7d30b57f15617f679a20aa1…
Nekem ez gyanús, mert nem foglalkozik vele, hogy sikerült-e updatelni sort vagy sem. Az igazán korrekt az lenne ha update után nyom egy selectet és összehasonlítja a rekordot a db-ben azzal amivel be akarta updatelni.
Node1 | Node2
Av0 | Av0
Bv0 | Cv0 <- erre változtatunk
------------- verzió check ----------
getEntry().version := 0 | getEntry().version := 0
minden ok | minden ok
---------------- commit ------------------
update v=1 where v=0 OK |
--- szerk: ezek biztosan egymás után történnek mivel az update atomi ----
update v=1 where v=0 SEMMI <- ezt le kéne kezelni de ilyen nincs a kódban, legalábbis onnan nem dob OptimisticLockingException-t
Bv1
--------------------------
vagy itt kéne megnéznie, hogy Bv1 ?= Cv0 és akkor kiderülne, hogy
- A hozzászóláshoz be kell jelentkezni
Ennél komplexebb azért a Hibernate kódja... egy csomó saját Locking exception van, amit aztán konvertál az end user felé.
- A hozzászóláshoz be kell jelentkezni
Nyilván, de a végén akkor is OptimisticLockingException-nek kéne belőle lenni ha egy optimistic lock sértés, de a github source alapján nincs olyan hely ahol ilyet csinál. Szóval nekem továbbra is gyanús, hogy ha az időzítés pont úgy jön ki, akkor nem tökéletes.
- A hozzászóláshoz be kell jelentkezni
Nyilván, de a végén akkor is OptimisticLockingException-nek kéne belőle lenni ha egy optimistic lock sértés, de a github source alapján nincs olyan hely ahol ilyet csinál.
Hm... tehát sikerült a Hibernate komplex és összetett forrásából pár perc alatt levezetned azt, hogy nincs olyan hely, ahol ez kijön, míg OP szerint:
Egyébként tesztekkel nem sikerült még előidéznünk, hogy nálunk duplikálódjón egy csomag. Mindig Optimistic lock keletkezett.
Szerintem kicsit több időt kellene azért eltölteni a Hibernate forrását elemezve, hogy ilyen kijelentéseket tegyél...
- A hozzászóláshoz be kell jelentkezni
Sajna véges időm van Hibernate forrást nézegetni, ezért abból kell levonnom következtetést amire ez alatt jutok.
Nem azt mondtam, hogy nincs olyan hely hanem, hogy gyanús. Kizárod az elméleti lehetőségét, hogy előálljon az a helyzet amit példaként írtam a jelenlegi információink alapján?
- A hozzászóláshoz be kell jelentkezni
Nézd, idén lesz 22 éves a Hibernate, én első-második és sokadik körben is kizárnám azt, hogy 22 év alatt ne derült volna ki és/vagy nem dokumentálták le, hogy bizonyos esetekben az optimistic lock nem működik.
- A hozzászóláshoz be kell jelentkezni
Nyilván nagyobb az esély rá, hogy én tévedek és nem a Hibernate szar :)
Ettől függetlenül, HA feltesszük, hogy csak a verziót ellenőrizzük - providertől függetlenül - akkor előfordulhat a fentebb írt hibás működés szerinted?
- A hozzászóláshoz be kell jelentkezni
Ez szerintem rossz módszer, hibás kimenettel.
A "nem tudom" inkább helyes kimenet.
Gábriel Ákos
- A hozzászóláshoz be kell jelentkezni
Egy kicsit tovább mennék, bár nem tudom, hogy ez segít-e:
https://github.com/hibernate/hibernate-orm/blob/main/hibernate-core/src…
Itt látszik, hogy amikor nyom egy getCurrentVersion()-t, akkor szépen felolvassa az adatbázisból az éppen aktuális verziót.
- A hozzászóláshoz be kell jelentkezni
Ad1: használj szekvenciá(ka)t
Ad2: tárold külön a semver értékeit
Ad3: legyen computed column a full version string
mindez atomi.
Az ORM sokszor az ördög maga. Kritikus dolgokra mindig ott az SQL, de azt már sajnos elfedik és sokan nem is akarják megérteni. Nem feltétlenül neked írom, de számomra az ORM tanulási görbéje lehet h meredekebb, de a facepalm és a debug faktora is. :-)
- A hozzászóláshoz be kell jelentkezni
Az ORM-et leginkabb csak code completion-re es atomic CRUD-ra kene hasznalni.
- A hozzászóláshoz be kell jelentkezni
Megvan a helye a JPA-nak, ami nem csak egy ORM, ugye. A nagyobb probléma általában abból van, hogy olyakor és olyanra is használják, amire nem kellene; illetve a kisebb probléma általában abból van, hogy olyankor és olyanra nem használják, mikor és amire lehetne. És akkor a végkövetkeztetés az, hogy JPA a szar, pedig szimplán csak nem értenek hozzá. Ez sok mindenre igaz, csak a JPA esetén igen nagyot is lehet szopni.
- A hozzászóláshoz be kell jelentkezni
dehátpedig mixing sql és jpa implementációért/alkalamzásért botütés jár közszemlén a daily standupon!!!444 négy
Olyan hogy JPA melllett nativ sql megoldásokat _merj_ alkalmazni, mindkettőhöz érteni kell. Abban az országban, ahol fontosfile_final2_veglegesv4_utolso_geza.xlsx tök normális :-)
- A hozzászóláshoz be kell jelentkezni
dehátpedig mixing sql és jpa implementációért/alkalamzásért botütés jár közszemlén a daily standupon!!!444 négy
Miért ne lehetne? A legnagyobb hülyeség az ilyen "nálunk ezt nem lehet" és "mi nem szoktuk" jellehű önkorlátozás valami múltbeli szokásjog alapján, aminek az oka már rég a ködbe veszett.
Olyan hogy JPA melllett nativ sql megoldásokat _merj_ alkalmazni, mindkettőhöz érteni kell.
Igen. És?
- A hozzászóláshoz be kell jelentkezni
Lehet. Én is ezt vallom. De amikor a fent emlitett entity cache meg egyéb dolgok kapcsan mindenki megijed, hogy jajj KÉTFÉLE móron akarjuk szegény perzisztens layer állapotát bizergalni, jön a sikítás meg a futás szaladás. :-)
Hirtelen át kell ugye gondolni hol kell lehet invalidálni a cache-t, egyáltalán kell-e oda ORM vagy csak lusták vagyunk. Esetleg az egészet wrappelni kéne feljebb egy saját AdatElérőManagelő rétegbe h "kint" ne kelljen foglalkozni vele? Ekkor a teljes adat szerkezetet ismerni kell állapotostul elévüléstül életciklusostúl. Pedig csak egy entity.save() volt eddig. :)
ezt a Crud muveletek final2.docx ben olvastan, ami lehet nem az utolso valtozat!:-)
- A hozzászóláshoz be kell jelentkezni
Ezzel nagyjabol egyetertek.
A JPA reszleteit kevesbe ismerem, de egy rakas ORM feature-nek in general leteznie sem kene, mert a letezese is arra batorit fejlesztoket, hogy arra hasznaljak, amire nem kellene. :)
- A hozzászóláshoz be kell jelentkezni
Ezzel még a programnyelvek vannak így :)
- A hozzászóláshoz be kell jelentkezni
No. Kicsit beszélgettem ChatGPT barátunkkal (aki eléggé szeret félrebeszélni és tévutakra vezetni sajnos). Kb. ugyanoda lukadtunk ki a Pessimistic lock-al mint az optimistic lock-al. Az oka egyszerű. A különböző Entity Cache-k különböző állapotokat tárolhatnak és nem mindig vánszorog le szerinte a pessimistic lock sem a DB szintre és nem is mindig vánszorognak onnan fel a friss adatok, ha pl. a cache-ből szedi ki. Valamint az egész tranzakció végéig futhat több példány ismét, mert sokszor csak akkor tolja le a DB szintre a write lock-ot így akkor derül csak ki, hogy ütközés van.
Valami olyasmit javasolt végül, hogy külön tranzakcióban nyomjam le a foglaltságot a DB-be és külön EntityMAnager-ben:
@Stateless
public class ControlService {
@PersistenceContext
private EntityManager entityManager;
private static final String CONTROL_NAME = "processing_control";
public boolean isProcessing() {
EntityManager em = entityManager.getEntityManagerFactory().createEntityManager();
try {
em.getTransaction().begin();
Control control = em.find(Control.class, CONTROL_NAME, LockModeType.PESSIMISTIC_WRITE);
if (control == null) {
control = new Control();
control.setName(CONTROL_NAME);
control.setStatus("fut");
control.setLastStarted(new Date());
em.persist(control);
em.getTransaction().commit();
return false;
} else {
if (control.getStatus() == null) {
control.setStatus("fut");
control.setLastStarted(new Date());
em.merge(control);
em.getTransaction().commit();
return false;
} else {
em.getTransaction().commit();
return true;
}
}
} catch (Exception e) {
em.getTransaction().rollback();
// handle exception
} finally {
em.close();
}
return false;
}
public void finishProcessing() {
try {
Control control = entityManager.find(Control.class, CONTROL_NAME, LockModeType.PESSIMISTIC_WRITE);
control.setStatus(null);
entityManager.merge(control);
} catch (Exception e) {
// handle exception
}
}
}
Ez a megoldás sem tűnik jónak, mert ha jól tudom az EntityCache az EntityManagerFactory-nként van. Tehát megint csak beleesek a különböző Entity Cache problémáiba. Eddig volt olyan helyem ahol volt entity cache de csak egy nagy monolitikusban, volt ahol ki volt kapcsolva, ilyen még nem volt, hogy van is meg nincs is. :)
Esetleg egy külön DS megoldhatja ezt a gondot?
- A hozzászóláshoz be kell jelentkezni
és nem mindig vánszorog le szerinte a pessimistic lock sem a DB szintre
Ne higgy a ChatGPT-nek, az egy olyan senior kolléga, aki időnként trollkodik. Ez elég nagy baj lenne, ha a tranzakcióban nem vándorolna le a lock az adatbázisba.
- A hozzászóláshoz be kell jelentkezni
Igen, már tapasztaltam. :) Nemrég megkérdeztem máshogy. Erre eléggé mást válaszolt:
Igen, ha egy tranzakcióban futtatja az
em.find(ControlTable.class, "PROCESS_CONTROL", LockModeType.PESSIMISTIC_WRITE)
metódust, akkor a lock csak a tranzakció végén kerül érvényesítésre, amikor a tranzakció commit-olódik. A lockot addig tartja a JPA, hogy a tranzakció lefutása során ne lehessen más tranzakcióknak hozzáférni az adatokhoz.
Mondjuk még ez is félreérthető volt, így még egyszer rákérdezve már azt a választ adta, hogy amikor kiadjuk a find-ot, akkor direktbe bekérdez a DB-be. Nem használja a cache-t, mert lock is van a metódus hívásban. És attól kezdődően él a lock a DB szinten is a tranzakció végéig.
- A hozzászóláshoz be kell jelentkezni
Én a helyedben JPA specifikációt olvasnék inkább... de te tudod.
- A hozzászóláshoz be kell jelentkezni
Megtaláltam. Valóban jobb mint a ChatGPT találgatásaira hagyatkozni. :)
A ChatGPT sokszot azt a választ adja amit úgy érzékel, hogy hallani szeretnék. De ez programozásban nem túl előremutató.
- A hozzászóláshoz be kell jelentkezni
A ChatGPT konkrétan így van kitalálva, tehát ez feature és nem bug :)
- A hozzászóláshoz be kell jelentkezni
A chatgpt egyelőre én még nem használnám programozáshoz. :) De nem tudom meddig lesz ez érvényes, simán lehet hogy 1-2 év múlva már használható lesz.
- A hozzászóláshoz be kell jelentkezni
Igen. Néha meglepően jó válaszokat ad. Elég gyakran viszont félre visz.
- A hozzászóláshoz be kell jelentkezni
Egyszerű és triviális dolgokra használható már, mint például egy kicsit komplexebb mock REST hívást tenni egy frontend mögé.
- A hozzászóláshoz be kell jelentkezni
A locking nem kizárólag adatbázis (pláne nem kizárólag RDBMS vagy SQL) téma.
Érdemes az elméleti alapjaival tisztába jönni először és utána ránézni a konkrét implementációra hogy az mennyire bugos.
Az adott esetben bugos implementáció nem az elvet minősíti.
A pessimistic lock az biztosan sorba állít és biztosan van benne egy drága lockolás. Az egy másik kérdés hogy mennyire durva a lock (table lock vs row-level lock például)
Az optimistic lock nem biztos hogy sorba állít viszont ha megpukkan akkor még az előzőnél is drágább helyrerakni a dolgokat.
Mind runtime drágább mint kódolásilag.
Gábriel Ákos
- A hozzászóláshoz be kell jelentkezni
Ja igen, komplex téma esetén viszonylag könnyű az optimistic lockinggal indult témát belefojtani egy nem triviálisan látható pessimistic lockba, így drága is lesz megcsinálni és lassú is lesz.
Gábriel Ákos
- A hozzászóláshoz be kell jelentkezni
Ha tudnád hogy hány feldolgozó szál fut párhuzamosan, akkor egyszerűen modulo-val szűrhetnéd hogy a szálak ne lépjenek egymás lábára, mind csa a saját tortaszeletével foglalkozzon .
- A hozzászóláshoz be kell jelentkezni
Másolj ide be légyszi két ugyanolyan rekordot amit beírt a rendszer és nem kellett volna.
- A hozzászóláshoz be kell jelentkezni
A fent írt utasítás a következő kontextusban működik:
for (siker=0, error=0; !siker && !error; ) {
SELECT ...,version INTO ..., :version FROM table WHERE id=:id;
...új állapot előállítása...
UPDATE table SET ..., version= :version+1
WHERE id=:id AND version=:version;
if (sqlca.sqlcode<0) error= 1;
else if (updated_rows==1) siker= 1;
}
Az 'optimizmus' ebben az esetben azt jelenti, hogy a rekordot nem zároltuk, hanem bízunk abban, hogy nem pont akkor módosítja valaki más, amikor mi is dolgozunk a tétellel.
- A hozzászóláshoz be kell jelentkezni
Így van!
Nem bonyolult az Optimistic Lock ;-)
- A hozzászóláshoz be kell jelentkezni