Açık, salt okunur bir PostgreSQL işlemi, SELECT komutu işlem sona erene kadar bir ACCESS SHARE tablo kilidi tuttuğu için DROP TABLE komutunu engelleyebilir. Silme işlemi bununla çakışan bir ACCESS EXCLUSIVE kilidi gerektirir; bu nedenle sorgu dönmüş olsa bile bekler. PostgreSQL: Açık Kilitleme
Bu kılavuz, Mac’te bu bekleme durumunun nasıl yeniden oluşturulacağını, engelleyen oturumun nasıl belirleneceğini ve işlemin node-postgres’te doğru şekilde nasıl sonlandırılacağını gösterir. Yalnızca sentetik makale satırları kullanır. SQL, bu makale için alınan resmî güncel belgelerin sunduğu sürüm olan PostgreSQL 18’i hedefler; sürüme özgü ayarları uygulamadan önce sunucunuzun karşılık gelen kılavuzuna başvurun.
PostgreSQL kilitleri açısından salt okunur ne anlama gelir?
READ ONLY, bir işlemin hangi komutları yürütebileceğini kısıtlar. Örneğin, sıradan tablolarda değişiklik yapılmasına ve DROP TABLE gibi komutlara izin vermez. Okuma işlemlerini tablo kilidi almaktan muaf tutmaz. Bu senaryoda okuyucu ile silme işlemini denemeye çalışan oturum ayrı işlemlerdir. PostgreSQL: SET TRANSACTION
Normal bir SELECT, başvurulan tablolarda otomatik olarak ACCESS SHARE kilidi alır. DROP TABLE ise bu kilitle çakışan ACCESS EXCLUSIVE kilidini gerektirir. Kilitler normalde işlem sona erene kadar tutulur; belgelenmiş bir istisna, kilit alınmadan önce oluşturulmuş bir kaydetme noktasına geri dönülmesidir. Aşağıdaki örnekte kaydetme noktası kullanılmaz. PostgreSQL: Açık Kilitleme
Buradaki temel ayrım, sorgunun tamamlanması ile işlemin tamamlanması arasındadır. Terminalinizde makale satırlarını görmek, sorgunun döndüğünü gösterir. Sorguyu çevreleyen işlemin de sona erip ermediğini kontrol edin. psql içinde otomatik onay normalde etkindir; ancak açık bir BEGIN, siz bitirene kadar işlemi açık tutar. PostgreSQL: psql
Mac’te engellenen silme işlemini nasıl yeniden oluşturabilirsiniz?
Mac’inizin Terminal uygulamasında psql zaten kullanılabilir durumdayken, mevcut bir yerel PostgreSQL 18 test veritabanını kullanın. Aynı veritabanına bağlı üç Terminal sekmesi açın. Bunlara A, B ve C adlarını verin. Bunlar ayrı bağlantılar olmalıdır; ayrı düzenleyici bölmeleri tek başına ayrı bağlantı oluşturmaz.
Aşağıdaki bağlantı komutu, yerel test veritabanınızın adının postgres olduğunu varsayar. Gerekirse mevcut test veritabanınızın adını yazın. Komutu her sekmede çalıştırın. -X seçeneği, kişisel bir psql başlangıç dosyasının yüklenmesini önler. PostgreSQL: psql
psql -X -d postgres
Her bağlantıda otomatik onayı açıkça etkinleştirin ve sunucu sürümünü kontrol edin. Aşağıdaki bloklar sıralı bir uygulamadır: sonraki bloklar, önceki adımlarda oluşturulan kuruluma ve oturum durumuna bağlıdır.
\set AUTOCOMMIT on
SHOW server_version;
Sentetik makale tablosunu oluşturun
C sekmesinde kurulum komutlarını bir kez çalıştırın. Kullanılmayan bir tablo adı seçin: public.article_lock_demo zaten varsa durun ve örneklerin tamamında tutarlı şekilde başka bir ad kullanın. Kurulum, mevcut bir tabloyu bilerek silmez.
CREATE TABLE public.article_lock_demo (
id integer PRIMARY KEY,
title text NOT NULL
);
INSERT INTO public.article_lock_demo (id, title)
VALUES
(1, 'Choosing a notebook'),
(2, 'Organizing a reading list');
Okuyucu işlemini açık bırakın
A sekmesinde bu bloğu çalıştırın ve bağlantıyı komut isteminde açık bırakın. Henüz onaylamayın.
SET application_name = 'article_reader_demo';
BEGIN READ ONLY;
SHOW transaction_read_only;
SELECT id, title
FROM public.article_lock_demo
ORDER BY id;
transaction_read_only ifadesinin on olarak görünmesini ve ardından iki sentetik satırın gelmesini bekleyin. Okuma tamamlanmıştır, ancak açık işlem hâlâ devam etmektedir.
Başka bir bağlantıdan silmeyi deneyin
B sekmesinde aşağıdaki bloğu çalıştırın. DROP TABLE komutunu başka bir komut eklemeden son ifade olarak gönderin.
SET application_name = 'article_drop_demo';
BEGIN;
SET LOCAL lock_timeout = '60s';
DROP TABLE public.article_lock_demo;
Açık kaldığı sürece silme işleminin beklemesi gerekir. Örnek amaçlı 60 saniyelik sınır, bekleme durumunu incelemeniz için zaman tanır; her durumda kullanılması önerilen genel bir ayar değildir. lock_timeout, kilit almak için çok uzun süre bekleyen bir ifadeyi iptal eder ve her kilit alma denemesi için ayrı ayrı uygulanır. PostgreSQL: İstemci Bağlantısı Varsayılanları
Silme komutu döndükten sonra B’nin açık işlemini sürdürün. Silme başarılı olsa bile gösterim tablosunu korumak için daha sonra işlemi geri alacaksınız. DROP TABLE, işlemi onaylandığında tabloyu ve ilişkili dizinleri ile kısıtlamaları kaldırır. PostgreSQL: DROP TABLE
Silme işlemini hangi oturumun engellediğini nasıl kanıtlarsınız?
B beklerken C’de sonraki sorguyu çalıştırın. Bu sorgu, iki gösterim bağlantısını belirler ve PostgreSQL’e hangi oturumların her bir bağlantının kilit isteğini engellediğini sorar. pg_blocking_pids(), engelleyen işlem kimliklerinden oluşan bir dizi döndürür; işlem engellenmiyorsa boş bir dizi döndürür. PostgreSQL: Sistem Bilgisi İşlevleri ve İşleçleri
SELECT
pid,
application_name,
state,
xact_start,
wait_event_type,
wait_event,
pg_blocking_pids(pid) AS blocking_pids,
query
FROM pg_stat_activity
WHERE datname = current_database()
AND application_name IN (
'article_reader_demo',
'article_drop_demo'
)
ORDER BY application_name;
A’nın idle in transaction durumunda görünmesini bekleyin: açık bir işlemi vardır, ancak sorgu yürütmüyordur. B beklerken Lock bekleme olayı türüyle birlikte active durumunda görünebilir. PostgreSQL, yürütme durumunu ve bekleme olaylarını birbirinden bağımsız olarak belgeler; dolayısıyla tek başına active, bir komutun ilerlediğini göstermez. PostgreSQL: Kümülatif İstatistik Sistemi
Ardından gerçek tablo kilidi isteklerini inceleyin. A’nın işlemini bitirmeden önce bunu C’de çalıştırın.
SELECT
a.application_name,
l.pid,
l.mode,
l.granted
FROM pg_locks AS l
JOIN pg_stat_activity AS a ON a.pid = l.pid
WHERE l.locktype = 'relation'
AND l.database = (
SELECT oid
FROM pg_database
WHERE datname = current_database()
)
AND l.relation = 'public.article_lock_demo'::regclass
ORDER BY a.application_name, l.mode;
Aşağıda beklenen örüntü gösterilmiştir; bu, gerçek bir çalıştırmadan alınmış çıktı değildir. pg_locks içinde granted = true, işlemin kilidi tuttuğu; false ise kilidi beklediği anlamına gelir. PostgreSQL: pg_locks
| Oturum | Kilit modu | granted |
Yorum |
|---|---|---|---|
article_reader_demo |
AccessShareLock |
true |
Okuyucu tablo kilidini tutuyor |
article_drop_demo |
AccessExclusiveLock |
false |
Silme işlemi tablo kilidini bekliyor |
İki sorguyu birlikte tanılama sırası olarak kullanın: önce engelleme ilişkisini belirleyin, ardından ilgili tablonun tutulan ve istenen kilitlerini inceleyin. Bir oturumun boşta olması tek başına yeterli kanıt değildir; bu ilişki ve kilit satırları, oturumun bu belirli silme işlemiyle bağlantısını kurar.
B zaten zaman aşımına uğradıysa bekleyen kilit isteği artık görünmez. B’de ROLLBACK; çalıştırın, B’nin işlem bloğunu tekrarlayın ve A hâlâ açıkken hemen inceleyin.
Okuyucuyu nasıl serbest bırakıp gösterimi tamamlarsınız?
A’da salt okunur işlemi sonlandırın:
COMMIT;
B hâlâ bekliyorsa ve A onu engelleyen tek oturumsa silme işlemi artık tamamlanabilir. Sentetik tablonun kullanılabilir kalması için B’de gösterim amaçlı silme işlemini hemen geri alın:
ROLLBACK;
A’yı onaylamadan önce B zaman aşımına uğradıysa önce B’de ROLLBACK; çalıştırın. A sona erdikten sonra B’nin bloğunu tekrarlayın ve silme başarılı olduğunda yeniden ROLLBACK; çalıştırın. Böylece B’nin işlemini tamamlanmamış bırakmadan her iki olası sonucu da ele alırsınız.
Aşağıdaki karar yardımcısı, sorunun işlem ömründen kaynaklanıp kaynaklanmadığını veya başka bir açıklama olup olmadığını ayırt etmeye yardımcı olur. Etkinlik etiketleri, PostgreSQL’in belgelenmiş oturum durumlarını izler. PostgreSQL: Kümülatif İstatistik Sistemi
| Gözlem | Sonraki işlem |
|---|---|
A idle in transaction durumunda ve B’nin engelleyici dizisinde A’nın PID’si var |
A’nın bağlantısından işlemi sonlandırın |
| A sona ermiş, ancak B hâlâ engelleyici PID’ler bildiriyor | Kalan engelleyicileri inceleyin |
| B kilit zaman aşımı bildiriyor | Yeniden denemeden önce B’nin açık işlemini geri alın |
| B bağımlılık hatası döndürüyor | Bunu kilit beklemesi olarak değerlendirmek yerine bağımlılıkları inceleyin |
| B hemen dönüyor | Okuyucu işleminin açık kalıp kalmadığını kontrol edin |
IF EXISTS eksik bir tablo durumunu ele alırken CASCADE, bağımlı nesnelerin kaldırılıp kaldırılmayacağını belirler. Bunların hiçbiri kilit beklemesi seçeneği değildir. Bu alıştırma için varsayılan bağımlılık davranışını koruyun; resmî DROP TABLE sözdiziminde CONCURRENTLY biçiminde bir seçenek yoktur. PostgreSQL: DROP TABLE
node-postgres salt okunur işlemi nasıl sonlandırmalıdır?
node-postgres ile BEGIN, işlemdeki her ifade ve son COMMIT veya ROLLBACK için havuzdan alınmış aynı istemciyi kullanın. Resmî işlem belgeleri, bir işlem için pool.query() kullanılmaması gerektiği konusunda açıkça uyarır; çünkü ifadeler farklı istemcilere gönderilebilir. node-postgres: İşlemler
İşlemin tamamlanmasını ve istemcinin serbest bırakılmasını uygulamada iki ayrı adım olarak ele alın. client.release(), havuzdan alınmış istemciyi havuzuna geri verir; bu çağrıdan önce işlemi bitirin. Geri alma başarısız olursa havuz API’si, release() işlevine doğruluk değeri taşıyan bir bağımsız değişken geçirerek istemcinin yok edilmesini destekler. node-postgres: Havuz API’si
Bu eksiksiz program için, adım adım anlatımdaki sentetik tabloyu kullanın. ES modüllerini ve AggregateError öğesini destekleyen bir Node.js çalışma zamanı kullanın ve çalışan bir proje dizinine pg yükleyin:
npm install pg
Aşağıdakini read-articles.mjs adıyla kaydedin. Bağlantısını psql için kullanılan yerel test veritabanıyla aynı olacak şekilde yapılandırın. node-postgres, PGDATABASE dâhil PostgreSQL bağlantı ortamı değişkenlerini destekler. node-postgres: Bağlanma
import pg from 'pg';
const { Pool } = pg;
const pool = new Pool({ connectionTimeoutMillis: 5000 });
async function main() {
try {
const client = await pool.connect();
let discard = false;
try {
await client.query('BEGIN READ ONLY');
const result = await client.query(
'SELECT id, title FROM public.article_lock_demo ORDER BY id'
);
await client.query('COMMIT');
console.table(result.rows);
} catch (error) {
try {
await client.query('ROLLBACK');
} catch (rollbackError) {
discard = true;
throw new AggregateError(
[error, rollbackError],
'Query and rollback failed'
);
}
throw error;
} finally {
client.release(discard);
}
} finally {
await pool.end();
}
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
PGDATABASE=postgres node read-articles.mjs
Program, satırları görüntülemeden önce işlemi onaylar, hata durumunda geri alır ve her iki durumda da istemciyi serbest bırakır. JavaScript sözdizimi Node.js ile denetlendi; araştırma ortamında PostgreSQL bulunmadığı için veritabanı adımları belgelere göre incelendi ancak çalıştırılmadı.
Tek ve bağımsız bir okuma için pool.query(), belgelenmiş kolaylık yoludur ve istemciyi havuzdan elle almayı önler. Göreviniz gerektiriyorsa açık işlem seçin ve ilgisiz dosya işleme veya masaüstü etkileşimlerini bu işlemin ömrünün dışında tutun. node-postgres: Havuz API’si
Tamamlanmamış bir okuyucu için hangi zaman aşımı kullanılır?
Zaman aşımlarını neyin beklediğine göre kullanın. lock_timeout, silme işleminin kilit alma bekleyişini sınırlar. statement_timeout, ifade yürütme süresini sınırlar; bu nedenle başarılı bir okumadan sonra uygulamanın komut göndermeyi bırakması, işlemi sonlandırmaz. idle_in_transaction_session_timeout, açık bir işlem içinde boşta bırakılmış oturumları özellikle sonlandırır. Bunlar PostgreSQL 18’de belgelenmiş ayarlardır; süreleri uygulamanızın beklenen iş yüküne göre belirleyin. PostgreSQL: İstemci Bağlantısı Varsayılanları
Bu görevde belirleyici olan, okuyucunun işleminin sona erip ermediğini kontrol etmektir. Engelleyen PID’yi doğrulayın, tablo kilitlerini inceleyin ve işlemi onu başlatan bağlantıda bitirin. node-postgres’te, başarılı bir okumanın ardından gelen sonraki tablo silme işleminin beklememesi için bu son işlem komutunu normal başarı ve hata yollarının parçası hâline getirin.
Kaynaklar
- 13.3. Açık Kilitleme — PostgreSQL Global Development Group
- SET TRANSACTION — PostgreSQL Global Development Group
- psql — PostgreSQL Global Development Group
- 19.11. İstemci Bağlantısı Varsayılanları — PostgreSQL Global Development Group
- DROP TABLE — PostgreSQL Global Development Group
- 9.27. Sistem Bilgisi İşlevleri ve İşleçleri — PostgreSQL Global Development Group
- 27.2. Kümülatif İstatistik Sistemi — PostgreSQL Global Development Group
- 53.13. pg_locks — PostgreSQL Global Development Group
- İşlemler — node-postgres
- Havuz API’si — node-postgres
- Bağlanma — node-postgres