Sobes.tech
Middle+

// кесте тауарлары: // ID | қарау саны // ----------- // 1 | 100 // 2 пайдаланушы бір уақытта тауарды қарауды бастады, оның id = 1 // және біздің дерекқорда екі параллель транзакция іске қосылды // нәтижесі қандай болатынын түсіндіру керек? postgress func IncrementView(ctx context.Context, db *sql.DB, id int64) error { tx, err := db.BeginTx(ctx, nil) if err != nil { return err } defer tx.Rollback() var cnt int err = tx.QueryRowContext(ctx, "SELECT cnt_view FROM goods WHERE id = $1", id, ).Scan(&cnt) if err != nil { return err } cnt++ _, err = tx.ExecContext(ctx, "UPDATE goods SET cnt_view = $1 WHERE id = $2", cnt, id, ) if err != nil { return err } return tx.Commit() }

sobes.tech AI

AI-дан жауап

Көрсетілген кодта екі параллель транзакция бір уақытта тауардың id=1 үшін cnt_view мәнін оқиды, оны 1-ге арттырады және қайта жазады.

PostgreSQL-де әдепкі оқшаулау деңгейі — Read Committed. Бұл әр транзакция тек басталған кезде бекітілген деректерді көреді дегенді білдіреді.

Сценарий:

  1. Екі транзакция да cnt_view = 100-ді оқиды.
  2. Екеуі де cnt_view-ды 101-ге арттырады.
  3. Екеуі де 101-ді жазуға тырысады.

Мәселе — жоғалған жаңарту (lost update). Екінші транзакция commit жасау кезінде блоктау қатесін (serialization failure) алады немесе бірінші аяқталғанша күтеді.

Осы мәселені шешу үшін, оқуды блоктау керек, мысалы, SELECT ... FOR UPDATE қолдану арқылы, сонда екінші транзакция бірінші аяқталғанша күтеді және жаңартылған мәнді оқиды.

Түзету мысалы:

err = tx.QueryRowContext(ctx, "SELECT cnt_view FROM goods WHERE id = $1 FOR UPDATE", id).Scan(&cnt)

Бұл жаңарту санын бірізділікпен жүргізуге және деректер жоғалмайтындығына кепілдік береді.