ACID tamoyillari. Kirish.

Jakhongir Soataliev
3 min readAug 15, 2023

--

Backend dasturchi sifatida hayotimizda relational(relyatsion) DB(ma’lumotlar bazasi) bilan ishlashga to’g’ri keladi. Ushbu ma’lumotlar bazasi bilan ishlashni o’ziga yarasha nozik jihatlari bor. Ushbu nozik jihatlardan biri bu bir necha foydalanuvchi tomonidan ayni ma’lumotni o’zgartirishga urinish hodisasidir. Misol uchun, sizda PRODUCTS nomli table(jadval) bor. Ushbu jadvaldagi ayni bir qatorni ikkita foydalanuvchi bir vaqtda o’zgartirishga urinsa nima bo’ladi? Shu kabi savollar ma’lumotlar bazasi bilan ishlashning ilk yillaridayoq paydo bo’lgan. Ko’pchiligimiz qilgan PET project(o’zimizning kompyuterlarimizda biror narsa o’rganish yoki boshqa maqsadlarda yoziladigan production yuzini ko’rmaslik ehtimoli yuqori bo’lgan project)larimizda bunday muammo kuzatilmaydi. Chunki, bu muammo paydo bo’lishi uchun bir nechta foydalanuvchilar tomonidan project(loyiha)miz ishlatib ko’rilishi lozim.

Ushbu muammoni yechishda qanday usul qo’llangan? Albatta, TRANSACTION(tranzaksiya). Avvalo, transaction nimaligiga bir nazar solsak. Transaction bu bir nechta sql buyruqlar ketma-ketligi hisoblanadi. Ular ma’lumotlar bazasiga o’zgartirish kiritish yoki ma’lumotlar bazasidan ma’lum turdagi ma’lumotlarni olish uchun yozilgan buyruqlar bo’lishi mumkin.

Biz ishlayotgan har qanday ma’lumotlar bazasiga jo’natgan query(so’rov)larimiz uchun alohida transaction yasaladi. Misol uchun, bizda yuqoridagi PRODUCTS table’i bor. Ushbu table’dan ma’lumotlarni olish uchun quyidagi sodda query’ni ishga tushiramiz:

SELECT * FROM PRODUCTS;

Ushbu query execute bo’lgan(ishga tushgan)da, bizga ma’lum turdagi ma’lumotlar qaytib keladi. Bu holatda transaction qatnashmayaptiku? Qanday qilib har bir query transaction orqali amalga oshadi deyish mumkin? Aslida yuqoridagi query DBga quyidagicha yetib boradi:

BEGIN TRANSACTION;
SELECT * FROM PRODUCTS;
COMMIT;

Yuqoridagi BEGIN TRANSACTION; buyrug’i transaction’ni ichiga kiradigan buyruqlarni boshlanishini bildiradi. Transactionni ichida bir yoki bir necha buyruqlar bo’lishi mumkin. COMMIT; esa transaction tugab, transactiondagi buyruqlar ketma-ketligini DBga apply qilish(ya’ni DBdagi barcha fordalanuvchilar uchun visible(ko’rinarli) bo’lishi)ni bildiradi. Sizda savol tug’ilishi mumkin: BEGIN TRANSACTION; buyrug’idan keyin. SELECT * FROM PRODUCTS; buyrug’ini bajarganimizda ushbu buyruq DBda bajarilmaydimi? Albatta bajariladi. Lekin bu bajarilish aslida “bajarib ko’rish” ya’ni qoralama(chernovik) sifatida bajarish. Ushbu bajarishni DBning boshqa foydalanuvchilari ko’rmay turadi. Aytaylik, DB bu — o’qituvchi, foydalanuvchilar bu — o’quvchilar. Table bu doska bo’lsa, doskaga o’zgartirish kiritish uchun avval “chernovik”da amallarni bajarib o’qituvchiga tekshiritirib olinadi. O’qituvchi ruxsat bersa, keyin doskaga yoziladi va buni hamma ko’radi. Tushunarliroq bo’lishi uchun buyruqni UPDATE ga o’zgartiramiz:

1)BEGIN TRANSACTION;
2)UPDATE PRODUCTS SET QUANTITY = QUANTITY - 10 WHERE ID = 1;
3)COMMIT;

Ushbu holatda: 2-qatordagi buyruq bajarilgan va hali 3-qator bajarilmagan bo’lsa, u holda boshqa foydalanuvchilar uchun IDsi 1 ga teng bo’lgan PRODUCTni QUANTITYsi(soni) hali 10taga kamaymadi, ya’ni doskaga yozilmagan bo’ladi. COMMIT; buyrug’i esa doskaga yozish hisoblanadi. Agar transactionni ichidagi buyruqni bajarishda xato kuzatilsachi? Unda nima bo’ladi? Unda ushbu transaction rollback(orqaga qaytariladi) qilinadi. Sababi, ushbu transactionni DBda bajarish imkoni mavjud emas. Boshida eslab o’tilgan muammoni transaction orqali hal qilsak bo’ladi deb aytdik. Ushbu muammoni transaction orqali hal qilish uchun transactional DB 4 ta asosiy tamoyilga asoslangan bo’lishi kerak: Ular ACID(Kislota) tamoyillari deyiladi. ACIDdagi har bir harf, bitta tamoyilni anglatadi:
A — atomicity
C — consistency
I — isolation
D — durability

Ushbu tamoyillarga keyingi maqolalarimizda alohida to’xtalib o’tamiz. Endi esa amaliy buyruqlar orqali transaction tushunchasini tushunishga harakat qilamiz:

Ushbu amaliy qismda PostgreSQL 14 ma’lumotlar bazasini boshqarish tizimidan foydalanildi.
1. PRODUCTS va SALES nomli table’lar hosil qilamiz:

CREATE TABLE PRODUCTS(id serial primary key,
name text,
price float,
quantity integer);

CREATE TABLE SALES(id serial primary key,
productId integer,
price float,
quantity integer);

2. PRODUCTS table’ga data qo’shamiz:

INSERT INTO PRODUCTS(name, price, quantity) VALUES('phone', 999.99, 150);

3. Qo’shilgan ma’lumotni tekshirib ko’ramiz:

SELECT * FROM PRODUCTS;

4. Tasavvur qilaylik, bizdan 10 ta telefon sotib olindi. Buni ikkala tableda ham ko’rsatishimiz kerak bo’ladi. Ya’ni, PRODUCTS dagi quantityni 10taga kamaytiramiz, SALES table’ga esa bitta row(qator) qo’shamiz.

UPDATE PRODUCTS SET quantity = quantity - 10 WHERE id = 1;
INSERT INTO SALES(productId, price, quantity) VALUES(1, 999.99, 10);

Ushbu operatsiyalarni istalgan biri xato tufayli bajarilmay qolsa, u holda ikkinchisi ma’nosini yo’qotadi. Shu sababli, bu operatsiyalar yoki birga bajarilishi kerak yoki umuman bajarilmasligi kerak. Buni amalga oshirish uchun ushbu operatsiyalarni bitta transaction ichiga joylashtiramiz. Agar ularni bitta transaction ichiga joylamasak, u holda, DB ularni alohidadan transaction ichiga joylab execute qiladi.

BEGIN TRANSACTION;
UPDATE PRODUCTS SET quantity = quantity - 10 WHERE id = 1;
INSERT INTO SALES(productId, price, quantity) VALUES(1, 999.99, 10);
COMMIT;

Endi ushbu ikki operatsiyani ikkisi ham bajarilishi yoki ikkisi ham bajarilmasligidan havotir olmasak ham bo’ladi. Sababi, bittasi xato tufayli bajarilmay qolsa, transaction commit bo’lmay(bazaga yozilmay) qoladi va oldingi bajarilgan operatsiyalar rollback bo’lib ketadi(orqaga qaytarilib ketadi).
Keyingi maqolamizda transaction’ning asosiy tamoyillaridan biri ATOMICITY — atomlilik haqida gaplashamiz.

Telegram kanal

--

--

Jakhongir Soataliev

Senior Software Engineer @ EPAM Systems | Leader of Java Community Uzbekistan