Пойгоҳи додаҳо ва SQL бо PostgreSQL

Китоби омӯзишии SQL ва PostgreSQL барои навомӯзон: аз мафҳуми пойгоҳи додаҳои релятсионӣ ва насби PostgreSQL бо Docker то SELECT, навъҳои додаҳо, JOIN, тарҳрезии ҷадвалҳо, гурӯҳбандӣ, CTE, функсияҳои равзанавӣ, транзаксияҳо ва индексҳо. Ҳамаи мисолҳо дар PostgreSQL 18 санҷида шудаанд; дар охири бобҳо машқҳо ва дар замима ҷавобҳо оварда шудаанд.
Агенти Зеҳнӣ · 19 октябри 2026 · 14 саҳифа
Боби 11. Транзаксияҳо
Транзаксияи пойгоҳи додаҳо як воҳиди ягонаи кор аст, ки аз як ё чанд амалиёт иборат мебошад.
Мисоли классикӣ — интиқоли пул аз як суратҳисоби бонкӣ ба суратҳисоби дигар аст. Транзаксияи пурра бояд мутобиқати маблағҳоро байни суратҳисоби фиристанда ва гиранда таъмин кунад.
Яъне агар аз суратҳисоби фиристанда маблағи X кам шавад, ба суратҳисоби гиранда бояд маҳз X илова шавад — на бештар ва на камтар.
Транзаксия дар PostgreSQL дорои чор хусусияти асосӣ мебошад, ки якҷоя ACID ном доранд:
| Хусусият | Маъно |
|---|---|
| Atomicity — атомӣ будан | Ҳамаи амалҳои транзаксия иҷро мешаванд ё ҳеҷ кадоми онҳо татбиқ намегарданд. |
| Consistency — мутобиқат | Тағйироти додаҳо бояд ба қоидаҳо ва маҳдудиятҳои пешакӣ муайяншуда мувофиқ бошанд. |
| Isolation — ҷудоӣ | Муайян мекунад, ки транзаксияҳои ҳамзамон тағйироти якдигарро чӣ гуна мебинанд. |
| Durability — пойдорӣ | Тағйироти транзаксияи тасдиқшуда ба таври доимӣ нигоҳ дошта мешаванд. |
Сохтани ҷадвали намунавӣ
Барои намоиш ҷадвали наверо бо номи accounts месозем:
DROP TABLE IF EXISTS accounts;
CREATE TABLE accounts (
id INT GENERATED BY DEFAULT AS IDENTITY,
name VARCHAR(100) NOT NULL,
balance DEC(15,2) NOT NULL CHECK (balance >= 0),
PRIMARY KEY (id)
);
Дар ин ҷадвал:
id— шиносаи худкор тавлидшавандаи суратҳисоб.name— номи соҳиби суратҳисоб.balance— бақияи маблағ.CHECK (balance >= 0)— манъ кардани бақияи манфӣ.
Оғоз кардани транзаксия
Агар берун аз транзаксияи ошкоро фармони SQL иҷро кунед, PostgreSQL онро ба таври худкор дар дохили транзаксия иҷро мекунад. Дар ҳолати маъмули autocommit, пас аз иҷрои муваффақ фармон худкор тасдиқ мешавад.
Масалан, фармони зерин ба ҷадвали accounts сатри нав илова мекунад:
INSERT INTO accounts (name, balance)
VALUES ('Bob', 10000);
Барои ошкоро оғоз кардани транзаксия яке аз фармонҳои зеринро истифода баред:
BEGIN TRANSACTION;
Ё:
BEGIN WORK;
Ё кӯтоҳтар:
BEGIN;
Масалан, фармонҳои зерин транзаксияи навро оғоз карда, суратҳисоби нав илова мекунанд:
BEGIN;
INSERT INTO accounts (name, balance)
VALUES ('Alice', 10000);
Дар ҷаласаи ҷорӣ, яъне ҳамон пайвасте, ки транзаксияро оғоз кардааст, тағйиротро дида метавонед:
SELECT
id,
name,
balance
FROM accounts;
Аммо агар бо пайвасти дигар ба сервери PostgreSQL ворид шуда, ҳамин дархостро иҷро кунед, сатри нави Alice ҳанӯз намоён намешавад. Барои ин равзанаи дуюми терминалро кушоед, ба ҷузвдони postgres-learning гузаред ва ҷаласаи нави psql-ро оғоз кунед:
docker compose exec db psql -U postgres -d analysis
Дар ҷаласаи дуюм иҷро кунед:
SELECT
id,
name,
balance
FROM accounts;
Сабаб ин аст, ки транзаксия ҳанӯз тасдиқ нашудааст.
Тасдиқ кардани транзаксия
Барои ба таври доимӣ татбиқ кардани тағйирот транзаксияро бо COMMIT тасдиқ мекунем.
Ҳар се шакли зерин як маъно доранд:
COMMIT WORK;
COMMIT TRANSACTION;
COMMIT;
Пас аз тасдиқ, ҷаласаҳои дигар низ метавонанд тағйиротро бубинанд:
SELECT
id,
name,
balance
FROM accounts;
Пас аз иҷрои муваффақи COMMIT, PostgreSQL пойдории тағйиротро таъмин мекунад, то онҳо ҳангоми қатъшавии ногаҳонии низом нигоҳ дошта шаванд.
Намунаи пурра:
-- Оғоз кардани транзаксия
BEGIN;
-- Илова кардани сатри нав
INSERT INTO accounts (name, balance)
VALUES ('Alice', 10000);
-- Тасдиқ кардани тағйирот
COMMIT;
Ин намуна тамоми равандро якҷо нишон медиҳад. Агар Alice-ро дар қадамҳои қаблӣ аллакай илова ва тасдиқ карда бошед, иҷрои дубораи он боз як сатр месозад.
Бекор кардани транзаксия
Агар хоҳед тағйироти ҳанӯз тасдиқнашударо бекор кунед, аз ROLLBACK истифода баред:
ROLLBACK;
Ё:
ROLLBACK TRANSACTION;
Ё:
ROLLBACK WORK;
Фармони ROLLBACK тағйироти дар дохили транзаксия анҷомдодаро бекор мекунад.
Масалан, дар намунаи зерин аз бақияи суратҳисоби id = 1 маблағи 1 000 кам мекунем, вале баъдан тағйиротро бекор менамоем:
-- Оғоз кардани транзаксия
BEGIN;
-- Кам кардани бақия
UPDATE accounts
SET balance = balance - 1000
WHERE id = 1;
-- Бекор кардани тағйирот
ROLLBACK;
Агар ҳоло додаҳои ҷадвалро гиред, бақия тағйир наёфтааст, зеро амалиёти кам кардани маблағ бекор шуд:
SELECT * FROM accounts;
Натиҷа:
| id | name | balance |
|---|---|---|
| 1 | Bob | 10000.00 |
| 2 | Alice | 10000.00 |
Интиқоли пул
Акнун ба мисоли аввали боб бармегардем: аз суратҳисоби Bob ба суратҳисоби Alice 1 000 мефиристем. Ин ду амал аст — аз як суратҳисоб кам кардан ва ба дигаре илова кардан — ва онҳо бояд якҷоя иҷро шаванд:
BEGIN;
-- Кам кардан аз суратҳисоби Bob
UPDATE accounts
SET balance = balance - 1000
WHERE id = 1;
-- Илова кардан ба суратҳисоби Alice
UPDATE accounts
SET balance = balance + 1000
WHERE id = 2;
COMMIT;
Натиҷа:
| id | name | balance |
|---|---|---|
| 1 | Bob | 9000.00 |
| 2 | Alice | 11000.00 |
Ҷамъи пул дар ҳар ду суратҳисоб пеш аз интиқол ва пас аз он 20 000 аст: пул на пайдо шуд, на гум.
Ба паёмҳои PostgreSQL пас аз ҳар UPDATE диққат диҳед: ҳар кадом бояд UPDATE 1 бошад. Транзаксия танҳо аз хатоҳо муҳофизат мекунад. Агар суратҳисоби id = 2 вуҷуд надошта бошад, фармони дуюм хато намедиҳад — он UPDATE 0 медиҳад, яъне ягон сатр тағйир наёфт. Дар ин ҳолат COMMIT танҳо кам шудани маблағи Bob-ро тасдиқ мекунад ва 1 000 гум мешавад.
Аз ин рӯ, барномае, ки интиқол анҷом медиҳад, бояд пас аз ҳар UPDATE санҷад, ки маҳз як сатр тағйир ёфтааст, ва дар акси ҳол ROLLBACK иҷро кунад. Атомӣ будан кафолат медиҳад, ки амалҳо якҷоя иҷро ё бекор мешаванд; дуруст будани худи амалҳоро бояд барнома таъмин кунад.
Акнун мебинем, ки агар дар мобайни транзаксия хато рух диҳад, чӣ мешавад. Кӯшиш мекунем ба Alice 20 000 фиристем, гарчанде Bob ҳамагӣ 9 000 дорад. Ин дафъа аввал ба Alice илова мекунем ва баъд аз Bob кам мекунем:
BEGIN;
UPDATE accounts
SET balance = balance + 20000
WHERE id = 2;
UPDATE accounts
SET balance = balance - 20000
WHERE id = 1;
Фармони аввал бомуваффақият иҷро мешавад. Аммо дуюм бақияи Bob-ро манфӣ мекунад ва маҳдудияти CHECK онро рад мекунад:
ERROR: new row for relation "accounts" violates check constraint "accounts_balance_check"
DETAIL: Failing row contains (1, Bob, -11000.00).
Пас аз хато PostgreSQL транзаксияро «вайроншуда» мешуморад ва фармонҳои дигарро қабул намекунад:
ERROR: current transaction is aborted, commands ignored until end of transaction block
Транзаксияро бо ROLLBACK анҷом диҳед. Агар COMMIT нависед ҳам, PostgreSQL ба ҷойи он ROLLBACK иҷро мекунад ва ҳамин калимаро ҷавоб медиҳад. Акнун ҷадвалро санҷед:
SELECT * FROM accounts ORDER BY id;
| id | name | balance |
|---|---|---|
| 1 | Bob | 9000.00 |
| 2 | Alice | 11000.00 |
Бақияи Alice низ тағйир наёфтааст, гарчанде фармони аввал бехато иҷро шуда буд. Ин атомӣ будан аст: ҳамаи амалҳои транзаксия иҷро мешаванд ё ҳеҷ кадоми онҳо. Бе транзаксия Alice 20 000-и иловагӣ мегирифт, ки аз ҳеҷ ҷо наомадааст.
Хулоса
Транзаксия якчанд амалро ба як воҳиди кор муттаҳид мекунад. Бо BEGIN онро оғоз мекунед, бо COMMIT тағйиротро доимӣ месозед ва бо ROLLBACK бекор мекунед. То тасдиқ, тағйирот танҳо дар ҷаласаи худи транзаксия намоён аст.
Ҳар куҷо ки якчанд тағйирот бояд якҷоя рӯй диҳад — интиқоли пул, сабти фармоиш бо ҳамаи сатрҳояш, кам кардани мол аз анбор ҳангоми фурӯш — онҳоро дар як транзаксия иҷро кунед. Маҳдудиятҳое, ки дар боби 8 омӯхтед, ҳамроҳи транзаксияҳо кафолат медиҳанд, ки додаҳо ҳеҷ гоҳ дар ҳолати нимтайёр намемонанд.
Дар боби оянда ба индексҳо бармегардем ва навъҳои дигари индексҳои PostgreSQL-ро меомӯзем.
Худатон бисанҷед
- Дар як транзаксия аз суратҳисоби Alice ба суратҳисоби Bob 500 интиқол диҳед. Пас аз ҳар
UPDATEпаёми PostgreSQL-ро санҷед. - Транзаксияро оғоз кунед, ҳамаи сатрҳои
accounts-ро боDELETE FROM accounts;нест кунед, шумораи сатрҳоро санҷед ва баъдROLLBACKиҷро кунед. Чанд сатр боқӣ монд?
Ҷавобҳо дар замима, бахши «Ҷавобҳо ба машқҳо», оварда шудаанд.

Барномасозӣ
Олами Афсонаҳо
Ахбор
Саломатӣ
Дунё