Поведението, което описвате, е нормално и се очаква във всяка транзакционна релационна база данни.
Ако PostgreSQL ви е показал стойността edited
за първия SELECT
би било погрешно да го направите - това се нарича "мръсно четене" и е лоша новина в базите данни.
PostgreSQL ще има право да чака при SELECT
докато не извършите ангажимент или върнете назад, но това не се изисква от SQL стандарта, не сте му казали, че искате да изчакате, и не трябва да чака поради някаква техническа причина, така че връща данните, които сте поискали за веднага. В края на краищата, докато не бъде ангажирано, тази update
съществува само един вид - все още може или не може да се случи.
Ако PostgreSQL винаги чакаше тук, тогава бързо ще се окажете в ситуация, в която само една връзка може да прави нещо с базата данни в даден момент. Не е добър за производителност и е напълно ненужен през по-голямата част от времето.
Ако искате да изчакате едновременна UPDATE
(или DELETE
), ще използвате SELECT ... FOR SHARE
. (Но имайте предвид, че това няма да работи за INSERT
).
Подробности:
SELECT
без FOR UPDATE
или FOR SHARE
клаузата не приема никакво заключване на ниво ред. Така че той вижда какъвто и да е текущият ангажиран ред и не се влияе от транзакции по време на полет, които може да променят този ред. Концепциите са обяснени в раздела MVCC на документите
. Общата идея е, че PostgreSQL е копиране при запис, с управление на версиите, което му позволява да върне правилното копие въз основа на това, което транзакцията или изявлението може да "види" в момента, в който е стартирано - това, което PostgreSQL нарича "моментна снимка".
В READ COMMITTED
моментните снимки на изолацията се правят на ниво оператор, така че ако SELECT
ред, COMMIT
промяна в него от друга транзакция и SELECT
отново ще видите различни стойности дори в рамките на една трансация. Можете да използвате SNAPSHOT
изолация, ако не искате да видите извършени промени след началото на транзакцията, или SERIALIZABLE
изолация за добавяне на допълнителна защита срещу определени видове взаимозависимости на транзакции.
Вижте главата за изолиране на транзакция в документацията .
Ако искате SELECT
за да изчакате текущите транзакции да се ангажират или да върнат промените в избраните редове, трябва да използвате SELECT ... FOR SHARE
. Това ще блокира заключването, взето от UPDATE
или DELETE
докато транзакцията, която е взела заключването, се върне назад или се ангажира.
INSERT
е различен обаче - кортежите просто не съществуват за други транзакции, докато не се ангажират. Единственият начин да изчакате едновременно INSERT
s е да вземете EXCLUSIVE
заключване на ниво таблица, така че да знаете, че никой друг не променя таблицата, докато я четете. Обикновено необходимостта да направите това обаче означава, че имате проблем с дизайна в приложението - приложението ви не би трябвало да се интересува ако има незаети insert
все още е в полет.
Вижте главата за изрично заключване в документацията .