CodeGym /Kurslar /SQL SELF /Transaksiyalarla işləyərkən tipik səhvlər

Transaksiyalarla işləyərkən tipik səhvlər

SQL SELF
Səviyyə , Dərs
Mövcuddur

Bu dərsdə biz transaksiyalarla işləyərkən baş verən tipik səhvlərə və onlardan necə qaçmağa baxacağıq. İnan, ən peşəkar SQL-ustası belə bəzən COMMIT yazmağı unudur! Sənə məsləhətlər verəcəyik ki, transaksiyalarda səhvlər sənin üçün nadir hal olsun.

Təəssüf (ya da bəlkə də xoşbəxtlikdən), verilənlər bazası — elə bir sehrli qala deyil ki, hər şey həmişə problemsiz işləsin. Transaksiya səhvləri — xüsusilə yeni başlayanlar üçün — olduqca tez-tez rast gəlinir. Gəlin onları detallı şəkildə araşdıraq.

COMMIT və ya ROLLBACK komandasının unudulması

Transaksiyanı bitirməyi unutmaq — əsl "janrın klassikası"dır. Təsəvvür elə restorandasansa, yemək sifariş etmisən, amma ofisiant çeki gətirməyi unudub. PostgreSQL dünyasında bu o deməkdir ki, verilənlər bazası "transaksiya vəziyyətində ilişib qalır", resursları tutur və digər əməliyyatları bloklayır.

Səhv nümunəsi:

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
-- Ups! Biz COMMIT və ya ROLLBACK əlavə etməyi unutduq.

Transaksiya "ilişəndə", resursun bloklanması bütün cədvələ yayıla bilər. Əgər verilənlər bazası admini vəziyyətin pis olduğunu bilirsə, onu "sərt" şəkildə bitirə bilər. Amma yaxşısı budur ki, heç bu vəziyyətə düşməyəsən.

Necə qaçmaq olar?

  • Transaksiyanı həmişə açıq şəkildə bitir: COMMIT və ya ROLLBACK.
  • Avtomatik olaraq ilişmiş transaksiyaları xatırladan client alətlərindən istifadə et.
  • Əgər transaksiyanı bitirməmisən və tətbiqi yenidən başladırsansa, verilənlər bazası avtomatik ROLLBACK edəcək, amma bu həmişə sistemin vəziyyəti üçün rahat olmur.

Səhv isolation səviyyəsinin seçilməsi

Isolation səviyyəsini seçmək bəzən darıxdırıcı formalıq kimi görünə bilər, amma o, anomaliyaların qarşısını almaqda əsas rol oynayır. Məsələn, əgər vacib maliyyə əməliyyatı üçün READ UNCOMMITTED istifadə edirsənsə, "çirkli" məlumatları oxuya bilərsən və onlar sonradan ləğv oluna bilər.

Nümunə:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN;
-- Başqa transaksiyanın dəyişdiyi məlumatları oxuyuruq
SELECT balance FROM accounts WHERE account_id = 1;
-- Başqa transaksiya ROLLBACK edəcək və sənin məlumatların etibarsız olacaq.

Necə qaçmaq olar?

  • Məlumatların tətbiqin üçün nə qədər vacib olduğunu müəyyən et.
  • Əksər hallarda "çirkli" oxumanın qarşısını almaq üçün READ COMMITTED istifadə et.
  • Dəyişikliklərin və ya phantom dataların qarşısını almaq kritikdirsə, REPEATABLE READ, SERIALIZABLE kimi daha sərt isolation səviyyələrindən istifadə et.

Transaksiya konflikti və bloklanmalar

Bəzən iki və ya daha çox transaksiya eyni məlumatı dəyişməyə çalışır. Belə halda PostgreSQL onlardan birini bloklayır, digəri bitənə qədər gözləyir. Bu isə deadlock (qarşılıqlı bloklanma) vəziyyətinə gətirib çıxara bilər.

Səhv nümunəsi:

-- Birinci transaksiya
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;

-- İkinci transaksiya
BEGIN;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 1;
-- Birinci transaksiyanı gözləyir...

Əgər hər iki transaksiya bir-birinə lazım olan resursları tutubsa, deadlock yaranır. PostgreSQL deadlock-u aşkar edəcək, transaksiyalardan birini səhvlə bitirəcək və belə mesaj verəcək:

ERROR: deadlock detected

Necə qaçmaq olar?

  • Transaksiyalarda əməliyyatların icra ardıcıllığını sabit saxla.
  • Transaksiyanın icra müddətini minimuma endir, bloklanma ehtimalını azaldırsan.
  • SERIALIZABLE isolation səviyyəsini yalnız həqiqətən lazım olanda istifadə et.

SAVEPOINT ilə səhv

SAVEPOINT — qismən geri qaytarma üçün əla alətdir, amma onu səhv istifadə etsən, qarışıqlıq yarada bilər. Məsələn, əgər savepoint-i azad etməyi (RELEASE SAVEPOINT) unutsan, artıq bloklanmalara və ya səhvlərə səbəb ola bilər.

Səhv nümunəsi:

BEGIN;
SAVEPOINT my_savepoint;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
ROLLBACK TO SAVEPOINT my_savepoint;
-- SAVEPOINT-i azad etməyi unutduq!

Necə qaçmaq olar?

  • SAVEPOINT artıq lazım deyilsə, onu silməyə əmin ol.
  • Çalış çoxlu savepoint yaratma, sorğuları çətinləşdirirsən.

Transaksiyaların xarici sistemlərlə uyğunsuzluğu

Təsəvvür elə ki, PostgreSQL-də transaksiya xarici sistemlərlə işləməyə çalışır: bildiriş göndərmək, API yeniləmək və s. Əgər xarici sistemdə nəsə alınmasa, dəyişiklikləri geri qaytarmaq çətin olacaq.

Nümunə:

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
-- Bildirişi göndərmək olmur: email-server cavab vermir.
COMMIT; -- Dəyişikliklər yadda saxlanıldı, amma bildiriş göndərilmədi.

Necə qaçmaq olar?

  • Mümkün qədər xarici sistemlərlə əməliyyatları izolyasiya et.
  • Xarici sistemlərlə koordinasiya üçün aralıq cədvəllər və ya task queue-lardan istifadə et.

Böyük transaksiyalardan yaranan səhvlər

Çoxlu əməliyyatları əhatə edən böyük transaksiyalar daha çox səhvlərə meyllidir: bloklanmalar, timeout-lar və deadlock-lar.

Nümunə:

BEGIN;
-- Bir neçə min update əməliyyatı
UPDATE orders SET status = 'tamamlandı' WHERE delivery_date < CURRENT_DATE;
COMMIT; -- Əhəmiyyətli vaxt apara bilər.

Necə qaçmaq olar?

  • Böyük transaksiyaları bir neçə kiçik transaksiyaya böl.
  • Məlumatları yeniləmək üçün batch-lərdən istifadə et.
  • Bir transaksiyada dəyişən məlumatların həcmini minimuma endir.

Səhvlərin yoxlanılmasının unudulması

Transaksiyadakı bütün SQL-sorğular uğurla keçməyə bilər. Məsələn, əməliyyatlardan biri səhv verərsə, bütün transaksiya uğursuz olacaq.

Nümunə:

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_id = -1; -- Səhv: account_id mövcud deyil.
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
COMMIT; -- Səhvə görə icra olunmur.

Necə qaçmaq olar?

  • Hər bir əməliyyatın nəticəsini həmişə yoxla.
  • Sorğularında və ya client kodunda error handling istifadə et.

ROLLBACK davranışının səhv başa düşülməsi

Bir çox proqramçı düşünür ki, ROLLBACK dəyişiklikləri ləğv edir və hər şeyi əvvəlki vəziyyətə qaytarır. Amma ROLLBACK yalnız cari transaksiyada işləyir.

Səhv düşüncə nümunəsi:

UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
ROLLBACK; -- Səhv! Bu işləmir, çünki əməliyyat transaksiyada deyildi.

Necə qaçmaq olar?

  • Unutma: BEGIN — dostundur, onsuz ROLLBACK gücsüzdür.
  • Kritik əməliyyatları həmişə transaksiyaya bürüyürsən.
1
Sorğu/viktorina
, səviyyə, dərs
Əlçatan deyil
Transaksiyaların izolasiya səviyyələrinə giriş
Transaksiyaların izolasiya səviyyələrinə giriş
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION