NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky
Tags for Laravel

Súbežné zápisy a integrita

Dvaja ľudia, ktorí ukladajú v tej istej chvíli, nikdy nevytvoria duplicitné štítky, neporušia limit typu, nepripoja zmazaný štítok ani nepokazia počet použití. Každé meniace volanie beží v transakcii na spojení modelu štítku; vonkajšia transakcia pri deadlocku zopakuje pokus trikrát a pri každom pokuse načíta riadky znova a udalosti sa spustia až po potvrdení vonkajšej transakcie. Vo vašej vlastnej transakcii sa zápis k nej pripojí a neopakuje sa — Laravel vnorenú transakciu nikdy neopakuje, takže rozhoduje vaša vonkajšia transakcia.

Poradie zámkov

Každý zápis zamyká v pevnom poradí a zámky riadkov štítkov berie jedným vzostupným prechodom podľa kľúčov, takže dva zápisy na seba nikdy nečakajú v kruhu:

ZápisZámky, v poradí
attach / detach / sync / clearPri názvoch voľného stromového typu najprv zámok tohto stromu. Potom vlastný riadok modelu, aby každé ďalšie čítanie videlo potvrdený zápis predchádzajúceho zapisovateľa a limit aj sync platili. Potom jeden prechod uzamkne každý riadok štítku, ktorého sa zápis dotkne — pomenované štítky, nesené štítky, ktoré odpája (vo vašej transakcii všetky nesené), a každý riadok, ktorý môže nový názov zmeniť: držiteľov slugov a v strome rodiča a podstrom zmazaného držiteľa. Nové voľné štítky vznikajú v savepointoch so zamykajúcim opätovným čítaním, pri štítkoch na pripojenie sa znova overí, že sú živé, a odpojenie znova prečíta, ktoré priradenia ešte nesie — len tie odstráni, zaráta a ohlási.
… vo vašej vlastnej transakciiNajprv sa uzamknú riadky štítkov, na ktoré ukazujú riadky spojovacej tabuľky modelu (podľa vašej snímky), a štítky, ktoré pripája; potom sa riadky spojovacej tabuľky prečítajú zamykajúcim čítaním, ktoré vždy vidí najnovšie potvrdené riadky, a štítok, ktorý odhalil novší riadok, sa uzamkne naposledy. Riadky štítkov pred riadkami spojovacej tabuľky — v tom istom poradí zamyká zmazanie aj obnova štítku.
Vytvorenie v strome (aj koreň a znovu vytvorený názov), presun, zoradenie, zmazanie s deťmi, obnovaNajprv riadok tag_locks stromu (jeden na typ a rozsah); potom jedným vzostupným prechodom každý riadok štítku, o ktorom zápis rozhoduje alebo ktorý mení — samotný štítok, jeho starého a nového rodiča, podstrom, súrodencov posunutých pozíciou (pri presune na neskoršiu pozíciu pod tým istým rodičom každého súrodenca za uvoľneným miestom), zmazaný štítok, ktorý názov vráti. Vo vašej transakcii sa tieto riadky potom čítajú zamykajúcim čítaním.
Zmazanie plochého štítkuRiadok štítku zamykajúcim čítaním — druhé zmazanie počká, potom ho nájde zmazaný a neurobí nič; potom znova zmazaný riadok v prechode podľa kľúčov, potom riadky spojovacej tabuľky a počty.
Premenovanie / úpravaRiadok štítku a držitelia každého slugu, ktorý môže zmena prevziať, jedným prechodom v poradí kľúčov.
tags:repair --pathsStrom po strome, vo vnútri zámku daného stromu.
tags:repair --countsDávky po 500 štítkoch; každá pred počítaním uzamkne svoje riadky štítkov v poradí kľúčov.

Keďže riadok modelu je prvý, aplikácia, ktorá v rámci vlastnej transakcie uzamkne model a potom pripojí nový názov, sa s balíkom nezablokuje. A keďže zápis štítkov vo vašej transakcii zamyká riadky štítkov pred riadkami spojovacej tabuľky, DB::transaction(fn () => $event->syncTags($labels, 'label')) sa nikdy nezablokuje so správcom, ktorý jedno z týchto označení maže.

Kedy môže deadlock ešte nastať

Databáza jednu stranu preruší; zápis vo vlastnej transakcii sa zopakuje, transakciu, ktorú ste otvorili vy, opakujete sami:

  • vo vašej transakcii štítok, ktorý k tomu istému modelu pripojila iná požiadavka až po vytvorení vašej snímky a ktorý sa práve v tej chvíli maže;
  • vo vašej transakcii zápis do stromu a zápis štítkov na dvoch štítkoch toho stromu, keď iná požiadavka po vytvorení vašej snímky presunula riadok do množiny zápisu do stromu — prechod číta množinu z tejto snímky a novší riadok sa uzamkne, až keď k nemu zápis dôjde;
  • voľný názov, ktorého zmazaný držiteľ má ešte zvyšné priradenie na tom istom modeli (obyčajné $tag->delete()), znovu vytvorený vo vašej transakcii v čase, keď správca tento štítok obnovuje.

Čo je zaručené

  • Dve súbežné attachTags() na type s jedným štítkom nikdy nenechajú modelu dve kategórie.
  • Dve súbežné vytvorenia toho istého názvu skončia jedným štítkom a DuplicateTagException — pri findOrCreate() dostanú obe ten istý štítok.
  • Dve súbežné zmazania jedného štítku ho zmažú raz a spustia jednu udalosť TagDeleted; druhé vráti zmazaný štítok.
  • Pripojenie súbežné so zmazaním toho istého štítku nikdy nepripojí zmazaný štítok (TagNotFoundException, „The tag is deleted.“).
  • Počty použití sa upravujú v tej istej transakcii ako riadky spojovacej tabuľky, presne o zapísané riadky, takže zostávajú presné; presné je aj prepočítanie opravou počas živej prevádzky.
  • Presuny, zoradenia a mazanie podstromov sa v jednom strome nikdy neprekrývajú a vo vašej transakcii vidia strom tak, ako ho nechal zapisovateľ, na ktorého čakali: žiadny cyklus rodičov, žiadne prehliadnuté nové dieťa, žiadna zastaraná cesta.
  • Odpojenie, ktoré čakalo na riadok štítku držaný mazaním, zaráta len priradenia, ktoré naozaj odstránilo.

MySQL a PostgreSQL

  • Vkladanie je obyčajný INSERT, nikdy INSERT IGNORE, ktorý by aj chybu cudzieho kľúča či orezania premenil na upozornenie; neúspešné vloženie beží v savepointe, takže PostgreSQL ponechá vonkajšiu transakciu použiteľnú.
  • Vo vnútri transakcie, ktorú ste otvorili — a ktorá si mohla snímku REPEATABLE READ v MySQL vziať skôr —, sa aktuálne priradenia aj každý riadok stromu, o ktorom zápis do stromu rozhoduje, čítajú zamykajúcim čítaním; agregácia sa číta ako najvyšší riadok, pretože PostgreSQL pri nej FOR UPDATE odmieta.
  • Posledná pozícia súrodenca je jediné zostávajúce obyčajné čítanie: zastaraná hodnota len zrovná dvoch súrodencov, ktorí sa potom zoradia podľa pozície a kľúča.
  • Kľúče zvonka sa pred akýmkoľvek SQL overia proti nakonfigurovanému typu kľúča — vrátane kľúča bigint mimo 64-bitového rozsahu —, pretože PostgreSQL by na nesúhlasiaci kľúč odpovedal chybou a MySQL by ho potichu pretypoval.

Každá udalosť implementuje ShouldDispatchAfterCommit: listenery sa spustia až po potvrdení zmeny a odvolaný zápis neohlási nič. Balík je testovaný proti PostgreSQL aj MySQL s paralelnými zápismi.

Zápisy mimo balíka

Hromadné mazanie modelov so štítkami, obyčajné $tag->delete(), import cez SQL či ručne upravené parent_id tieto záruky obídu. tags:doctor nájde, čo po nich zostane, a tags:repair to opraví — cesty a hĺbky, kľúče rozsahu, osirotené priradenia, priradenia na zmazaných štítkoch a počty použití — po dávkach, bezpečne aj pri živej prevádzke (pozrite Artisan príkazy).

Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

Ďalšie spôsoby podpory vrátane kryptomien

Odoslaním daru súhlasíte s našimi podmienkami prijímania darov.

Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.