---
title: "Súbežné zápisy a integrita — Tags for Laravel | Roundly"
description: "Ako zápisy štítkov, stromov a katalógu zostanú správne pri súbežných zápisoch — pevné poradie zámkov, jeden prechod podľa kľúčov, savepointy, opakovanie."
url: https://roundly-consulting.com/sk/open-source/navody/tags-for-laravel/subezne-zapisy
language: sk
---

[Všetky balíky](https://roundly-consulting.com/sk/open-source.md)

[Tags for Laravel](https://roundly-consulting.com/sk/open-source/navody/tags-for-laravel.md)

# 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ápis | Zámky, v poradí |
| --- | --- |
| attach / detach / sync / clear | Pri 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 transakcii | Najprv 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, obnova | Najprv 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, zmazaný štítok, ktorý názov vráti. Vo vašej transakcii sa tieto riadky potom čítajú zamykajúcim čítaním. |
| Premenovanie / úprava | Riadok štítku a držitelia každého slugu, ktorý môže zmena prevziať, jedným prechodom v poradí kľúčov. |
| `tags:repair --paths` | Strom po strome, vo vnútri zámku daného stromu. |
| `tags:repair --counts` | Dá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.
- 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](https://roundly-consulting.com/sk/podporte-nas.md)

Odoslaním daru súhlasíte s našimi [podmienkami prijímania darov](https://roundly-consulting.com/sk/podmienky-darov.md).

[Podporte našu open-source prácu (otvorí sa v novej karte)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Pridajte sa k nám na Patreone (otvorí sa v novej karte)](https://www.patreon.com/cw/roundly)

## 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.

[Ponuka do 48 hodín](https://roundly-consulting.com/sk/kontakt.md) [Prezrieť všetky balíky](https://roundly-consulting.com/sk/open-source/navody/tags-for-laravel.md)
