Transaksi PostgreSQL baca sahaja yang terbuka boleh menyekat DROP TABLE kerana SELECT memegang kunci jadual ACCESS SHARE sehingga transaksi berakhir. Pengguguran memerlukan kunci ACCESS EXCLUSIVE yang bercanggah, jadi ia menunggu—walaupun selepas pertanyaan selesai. PostgreSQL: Penguncian Eksplisit
Panduan ini menunjukkan cara menghasilkan semula penantian itu dari Mac, mengenal pasti sesi yang menyekat, dan menutup transaksi dengan betul dalam node-postgres. Panduan ini hanya menggunakan baris artikel sintetik. SQL menyasarkan PostgreSQL 18, versi yang digunakan oleh dokumentasi rasmi semasa yang dirujuk untuk artikel ini; rujuk manual yang sepadan dengan pelayan anda sebelum menggunakan tetapan khusus versi.
Apakah maksud baca sahaja untuk kunci PostgreSQL?
READ ONLY mengehadkan arahan yang boleh dilaksanakan oleh sesuatu transaksi. Contohnya, ia tidak membenarkan pengubahsuaian pada jadual biasa dan arahan seperti DROP TABLE. Namun, ia tidak mengecualikan operasi membaca daripada penguncian jadual. Dalam senario ini, pembaca dan sesi yang cuba menggugurkan jadual ialah transaksi yang berasingan. PostgreSQL: SET TRANSACTION
SELECT biasa memperoleh ACCESS SHARE secara automatik pada jadual yang dirujuk. DROP TABLE memerlukan ACCESS EXCLUSIVE, yang bercanggah dengan kunci tersebut. Kunci biasanya kekal sehingga transaksi berakhir; satu pengecualian yang didokumenkan ialah membuat rollback ke savepoint yang ditetapkan sebelum kunci diperoleh. Contoh di bawah tidak menggunakan savepoint. PostgreSQL: Penguncian Eksplisit
Perbezaan utamanya ialah antara pertanyaan selesai dengan transaksi selesai. Melihat baris artikel dalam terminal anda bermakna pertanyaan telah selesai. Semak sama ada transaksi yang mengelilinginya juga telah berakhir. Dalam psql, autocommit biasanya didayakan, tetapi BEGIN yang jelas memastikan transaksi terus terbuka sehingga anda menamatkannya. PostgreSQL: psql
Bagaimanakah anda boleh menghasilkan semula pengguguran yang tersekat pada Mac?
Gunakan pangkalan data ujian PostgreSQL 18 tempatan yang sedia ada, dengan psql tersedia dalam Terminal Mac anda. Buka tiga tab terminal yang disambungkan ke pangkalan data yang sama. Namakannya A, B dan C. Tab ini mesti menggunakan sambungan berasingan; panel editor yang berasingan sahaja tidak menjamin perkara itu.
Arahan sambungan berikut mengandaikan nama pangkalan data ujian tempatan anda ialah postgres. Gantikan dengan nama pangkalan data ujian sedia ada anda jika perlu. Jalankan arahan itu dalam setiap tab. Pilihan -X mengelakkan pemuatan fail permulaan peribadi psql. PostgreSQL: psql
psql -X -d postgres
Dalam setiap sambungan, dayakan autocommit secara eksplisit dan semak versi pelayan. Blok di bawah ialah panduan langkah demi langkah yang mengikut turutan: blok seterusnya bergantung pada persediaan dan keadaan sesi yang diwujudkan oleh blok sebelumnya.
\set AUTOCOMMIT on
SHOW server_version;
Cipta jadual artikel sintetik
Dalam tab C, jalankan persediaan sekali. Gunakan nama jadual yang belum digunakan: jika public.article_lock_demo sudah wujud, berhenti dan pilih nama lain untuk digunakan secara konsisten dalam semua contoh. Persediaan ini sengaja tidak membuang jadual yang sedia ada.
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');
Biarkan transaksi pembaca terbuka
Dalam tab A, jalankan blok ini dan biarkan sambungan berada pada promnya. Jangan commit lagi.
SET application_name = 'article_reader_demo';
BEGIN READ ONLY;
SHOW transaction_read_only;
SELECT id, title
FROM public.article_lock_demo
ORDER BY id;
Jangkakan transaction_read_only memaparkan on, diikuti dua baris sintetik. Operasi membaca telah selesai, tetapi transaksi eksplisit masih terbuka.
Cuba gugurkan jadual dari sambungan lain
Dalam tab B, jalankan blok berikut. Hantar DROP TABLE sebagai pernyataan terakhir tanpa menambah arahan lain selepasnya.
SET application_name = 'article_drop_demo';
BEGIN;
SET LOCAL lock_timeout = '60s';
DROP TABLE public.article_lock_demo;
Pengguguran sepatutnya menunggu selagi A masih terbuka. Had ilustrasi 60 saat memberi anda masa untuk memeriksa penantian itu; ini bukan tetapan universal yang disyorkan. lock_timeout membatalkan pernyataan yang menunggu terlalu lama untuk memperoleh kunci dan terpakai secara berasingan bagi setiap percubaan memperoleh kunci. PostgreSQL: Lalai Sambungan Klien
Biarkan transaksi eksplisit B terbuka selepas arahan pengguguran selesai. Anda akan membuat rollback kemudian supaya jadual demonstrasi kekal walaupun pengguguran berjaya. DROP TABLE membuang jadual serta indeks dan kekangan yang berkaitan apabila transaksinya di-commit. PostgreSQL: DROP TABLE
Bagaimanakah anda membuktikan sesi yang menyekat pengguguran?
Semasa B menunggu, jalankan pertanyaan seterusnya dalam C. Pertanyaan ini mengenal pasti dua sambungan demonstrasi dan meminta PostgreSQL menyatakan sesi yang menyekat permintaan kunci bagi setiap sambungan. pg_blocking_pids() mengembalikan tatasusunan ID proses yang menyekat, atau tatasusunan kosong jika proses itu tidak disekat. PostgreSQL: Fungsi dan Operator Maklumat Sistem
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;
Jangkakan A memaparkan idle in transaction: transaksi terbuka, tetapi tiada pertanyaan sedang dilaksanakan. B mungkin memaparkan active sementara menunggu, dengan jenis peristiwa menunggu Lock. PostgreSQL mendokumenkan bahawa keadaan pelaksanaan dan peristiwa menunggu adalah bebas antara satu sama lain; oleh itu, active sahaja tidak membuktikan bahawa sesuatu arahan sedang membuat kemajuan. PostgreSQL: Sistem Statistik Kumulatif
Seterusnya, periksa permintaan kunci jadual yang sebenar. Jalankan pertanyaan ini dalam C sebelum menamatkan transaksi A.
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;
Corak yang dijangka di bawah hanyalah ilustrasi, bukan output pelaksanaan yang dirakam. Dalam pg_locks, granted = true bermaksud proses itu memegang kunci; false bermaksud proses itu sedang menunggu kunci tersebut. PostgreSQL: pg_locks
| Sesi | Mod kunci | granted |
Tafsiran |
|---|---|---|---|
article_reader_demo |
AccessShareLock |
true |
Pembaca memegang kunci jadualnya |
article_drop_demo |
AccessExclusiveLock |
false |
Pengguguran menunggu kunci jadualnya |
Gunakan kedua-dua pertanyaan bersama-sama sebagai urutan diagnostik: mula-mula tentukan hubungan sekatan, kemudian periksa kunci yang dipegang dan diminta untuk jadual berkenaan. Sesi yang melahu sahaja bukan bukti yang mencukupi; hubungan sekatan dan baris kunci mengaitkannya dengan pengguguran khusus ini.
Jika B sudah tamat masa, permintaan kuncinya yang sedang menunggu tidak lagi akan dipaparkan. Jalankan ROLLBACK; dalam B, ulang blok transaksi B dan periksa dengan segera semasa A masih terbuka.
Bagaimanakah anda melepaskan kunci pembaca dan menamatkan demonstrasi?
Dalam A, tamatkan transaksi baca sahaja:
COMMIT;
Jika B masih menunggu dan A satu-satunya sesi yang menyekatnya, pengguguran kini boleh selesai. Dalam B, batalkan pengguguran demonstrasi itu dengan segera supaya jadual sintetik kekal tersedia:
ROLLBACK;
Jika B tamat masa sebelum anda membuat commit pada A, jalankan ROLLBACK; dalam B terlebih dahulu. Selepas A berakhir, ulang blok B dan kemudian jalankan ROLLBACK; sekali lagi apabila pengguguran berjaya. Langkah ini menangani kedua-dua kemungkinan tanpa membiarkan transaksi B tidak selesai.
Panduan keputusan berikut membantu membezakan isu jangka hayat transaksi daripada penjelasan lain. Label aktiviti mengikut keadaan sesi yang didokumenkan oleh PostgreSQL. PostgreSQL: Sistem Statistik Kumulatif
| Pemerhatian | Tindakan seterusnya |
|---|---|
A ialah idle in transaction, dan tatasusunan penyekat B mengandungi PID A |
Tamatkan transaksi A daripada sambungan A |
| A telah berakhir, tetapi B masih melaporkan PID yang menyekat | Periksa sesi lain yang masih menyekat |
| B melaporkan tamat masa kunci | Buat rollback pada transaksi eksplisit B sebelum mencuba semula |
| B mengembalikan ralat kebergantungan | Periksa kebergantungan dan jangan anggapnya sebagai penantian kunci |
| B selesai dengan serta-merta | Semak sama ada transaksi pembaca yang dimaksudkan masih terbuka |
IF EXISTS mengendalikan keadaan jadual tiada, manakala CASCADE mengawal pembuangan objek yang bergantung padanya. Kedua-duanya bukan pilihan untuk penantian kunci. Kekalkan tingkah laku kebergantungan lalai untuk latihan ini; sintaks rasmi DROP TABLE tidak mempunyai variasi CONCURRENTLY. PostgreSQL: DROP TABLE
Bagaimanakah node-postgres patut menutup transaksi baca sahaja?
Dengan node-postgres, gunakan satu klien yang telah diperoleh daripada pool untuk BEGIN, setiap pernyataan dalam transaksi dan COMMIT atau ROLLBACK yang terakhir. Dokumentasi rasmi transaksi secara jelas memberi amaran supaya tidak menggunakan pool.query() untuk transaksi kerana pernyataan boleh dihantar kepada klien yang berlainan. node-postgres: Transaksi
Anggap penyelesaian transaksi dan pelepasan klien sebagai dua langkah aplikasi yang berasingan. client.release() memulangkan klien yang telah diperoleh kepada pool; selesaikan transaksi sebelum memanggilnya. Jika rollback gagal, API pool menyokong pemusnahan klien dengan menghantar argumen bernilai benar kepada release(). node-postgres: API Pool
Untuk program lengkap ini, kekalkan jadual sintetik daripada panduan tadi. Gunakan masa jalan Node.js yang dipasang dan menyokong modul ES serta AggregateError, dan pasang pg dalam direktori projek kerja:
npm install pg
Simpan yang berikut sebagai read-articles.mjs. Konfigurasikan sambungannya ke pangkalan data ujian tempatan yang sama yang digunakan oleh psql. node-postgres menyokong pemboleh ubah persekitaran sambungan PostgreSQL, termasuk PGDATABASE. node-postgres: Menyambung
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 ini membuat commit sebelum memaparkan baris, membuat rollback jika berlaku kegagalan dan melepaskan klien dalam kedua-dua keadaan. Sintaks JavaScriptnya telah disemak dengan Node.js; panduan pangkalan data telah diteliti berdasarkan dokumentasi tetapi tidak dilaksanakan di sini kerana PostgreSQL tidak tersedia dalam persekitaran penyelidikan.
Untuk satu operasi membaca yang bebas, pool.query() ialah laluan mudah yang didokumenkan dan mengelakkan pemerolehan klien secara manual. Pilih transaksi eksplisit apabila tugasan anda memerlukannya, dan lakukan pemprosesan fail atau interaksi desktop yang tidak berkaitan di luar jangka hayat transaksi itu. node-postgres: API Pool
Apakah had masa yang sesuai untuk pembaca yang tidak menamatkan transaksi?
Gunakan had masa mengikut perkara yang sedang menunggu. lock_timeout mengehadkan tempoh menunggu pemerolehan kunci bagi arahan pengguguran. statement_timeout mengehadkan pelaksanaan pernyataan, jadi ia tidak menutup transaksi hanya kerana aplikasi berhenti menghantar arahan selepas operasi membaca berjaya. idle_in_transaction_session_timeout secara khusus menamatkan sesi yang dibiarkan melahu dalam transaksi terbuka. Ini ialah tetapan PostgreSQL 18 yang didokumenkan; pilih tempoh berdasarkan kerja yang dijangka oleh aplikasi anda. PostgreSQL: Lalai Sambungan Klien
Bagi tugasan ini, semakan penentunya ialah sama ada transaksi pembaca telah berakhir. Sahkan PID yang menyekat, periksa kunci jadual dan tamatkan transaksi pada sambungan yang memilikinya. Dalam node-postgres, jadikan arahan transaksi terakhir itu sebahagian daripada laluan biasa bagi kejayaan dan ralat supaya operasi membaca yang telah selesai tidak menyebabkan pengguguran jadual seterusnya terus menunggu.
Sumber
- 13.3. Penguncian Eksplisit — Kumpulan Pembangunan Global PostgreSQL
- SET TRANSACTION — Kumpulan Pembangunan Global PostgreSQL
- psql — Kumpulan Pembangunan Global PostgreSQL
- 19.11. Lalai Sambungan Klien — Kumpulan Pembangunan Global PostgreSQL
- DROP TABLE — Kumpulan Pembangunan Global PostgreSQL
- 9.27. Fungsi dan Operator Maklumat Sistem — Kumpulan Pembangunan Global PostgreSQL
- 27.2. Sistem Statistik Kumulatif — Kumpulan Pembangunan Global PostgreSQL
- 53.13. pg_locks — Kumpulan Pembangunan Global PostgreSQL
- Transaksi — node-postgres
- API Pool — node-postgres
- Menyambung — node-postgres