MVCC-3. Versi string

Dadi, kita wis nimbang masalah sing ana gandhengane isolasi, lan digawe mundur babagan ngatur data ing tingkat sing kurang. Lan pungkasane kita entuk bagean sing paling menarik - versi senar.

Header

Kaya sing wis dakkandhakake, saben baris bisa uga ana ing sawetara versi ing database. Siji versi kudu piye wae dibedakake saka liyane. Kanggo maksud iki, saben versi duwe rong tandha sing nemtokake "wektu" tumindak versi iki (xmin lan xmax). Ing kuotasi - amarga ora wektu kaya sing digunakake, nanging counter nambah khusus. Lan counter iki nomer transaksi.

(Minangka biasanipun, kasunyatan luwih rumit: nomer transaksi ora bisa nambah kabeh wektu amarga kapasitas dicokot winates saka counter. Nanging kita bakal katon ing rincian iki nalika kita njaluk pembekuan.)

Nalika baris digawe, xmin disetel menyang nomer transaksi sing ngetokake perintah INSERT, lan xmax ditinggalake kosong.

Nalika baris dibusak, nilai xmax saka versi saiki ditandhani karo nomer transaksi sing nindakake DELETE.

Nalika baris diowahi kanthi printah UPDATE, rong operasi sing bener ditindakake: DELETE lan INSERT. Versi baris saiki nyetel xmax padha karo jumlah transaksi sing nindakake UPDATE. Versi anyar saka senar sing padha banjur digawe; nilai xmin sawijining pas karo nilai xmax saka versi sadurungé.

Kolom xmin lan xmax kalebu ing header versi baris. Saliyane kolom kasebut, header ngemot liyane, contone:

  • infomask minangka seri bit sing nemtokake sifat versi iki. Ana cukup akeh; Kita bakal mboko sithik nimbang sing utama.
  • ctid punika link menyang sabanjuré, versi anyar saka baris padha. Kanggo paling anyar, versi paling anyar saka baris, ctid nuduhake versi iki dhewe. Angka kasebut nduweni wujud (x,y), ing ngendi x minangka nomer kaca, y minangka nomer indeks ing larik.
  • null bitmap - Nandhani kolom saka versi tartamtu sing ngemot nilai null (NULL). NULL dudu salah sawijining nilai jinis data normal, mula atribut kasebut kudu disimpen kanthi kapisah.

Akibaté, header cukup gedhe - paling 23 bita kanggo saben versi baris, lan biasane luwih amarga bitmap NULL. Yen tabel "sempit" (yaiku, ngemot sawetara kolom), nduwur sirah bisa njupuk luwih saka informasi migunani.

masang

Ayo dideleng kanthi rinci babagan operasi senar tingkat rendah, diwiwiti kanthi sisipan.

Kanggo eksperimen, ayo nggawe tabel anyar kanthi rong kolom lan indeks ing salah sijine:

=> CREATE TABLE t(
  id serial,
  s text
);
=> CREATE INDEX ON t(s);

Ayo lebokake siji baris sawise miwiti transaksi.

=> BEGIN;
=> INSERT INTO t(s) VALUES ('FOO');

Iki nomer transaksi saiki:

=> SELECT txid_current();
 txid_current 
--------------
         3664
(1 row)

Ayo katon ing isi kaca. Fungsi heap_page_items saka ekstensi pageinspect ngidini sampeyan entuk informasi babagan penunjuk lan versi baris:

=> SELECT * FROM heap_page_items(get_raw_page('t',0)) gx
-[ RECORD 1 ]-------------------
lp          | 1
lp_off      | 8160
lp_flags    | 1
lp_len      | 32
t_xmin      | 3664
t_xmax      | 0
t_field3    | 0
t_ctid      | (0,1)
t_infomask2 | 2
t_infomask  | 2050
t_hoff      | 24
t_bits      | 
t_oid       | 
t_data      | x0100000009464f4f

Elinga yen tembung heap ing PostgreSQL nuduhake tabel. Iki minangka panggunaan istilah aneh liyane - tumpukan dikenal struktur data, kang wis boten ing umum karo meja. Ing kene tembung kasebut digunakake ing pangertene "kabeh dibuwang bebarengan," minangka lawan indeks sing diurutake.

Fungsi kasebut nuduhake data "kaya", ing format sing angel dimangerteni. Kanggo ngerteni, kita bakal ninggalake mung bagean saka informasi lan decipher:

=> SELECT '(0,'||lp||')' AS ctid,
       CASE lp_flags
         WHEN 0 THEN 'unused'
         WHEN 1 THEN 'normal'
         WHEN 2 THEN 'redirect to '||lp_off
         WHEN 3 THEN 'dead'
       END AS state,
       t_xmin as xmin,
       t_xmax as xmax,
       (t_infomask & 256) > 0  AS xmin_commited,
       (t_infomask & 512) > 0  AS xmin_aborted,
       (t_infomask & 1024) > 0 AS xmax_commited,
       (t_infomask & 2048) > 0 AS xmax_aborted,
       t_ctid
FROM heap_page_items(get_raw_page('t',0)) gx
-[ RECORD 1 ]-+-------
ctid          | (0,1)
state         | normal
xmin          | 3664
xmax          | 0
xmin_commited | f
xmin_aborted  | f
xmax_commited | f
xmax_aborted  | t
t_ctid        | (0,1)

Iki sing ditindakake:

  • Nambahake nul kanggo nomer indeks supaya katon padha t_ctid: (nomer kaca, nomer indeks).
  • Deciphered negara pointer lp_flags. Punika "normal" - iki tegese pointer bener nuduhake versi senar. Kita bakal nliti makna liyane mengko.
  • Saka kabeh bit informasi, mung rong pasangan sing wis diidentifikasi nganti saiki. Bit xmin_committed lan xmin_aborted nuduhake manawa nomer transaksi xmin wis ditindakake (dibatalake). Rong bit sing padha nuduhake nomer transaksi xmax.

Apa sing kita deleng? Nalika sampeyan nglebokake baris, nomer indeks 1 bakal katon ing kaca tabel, nuduhake versi pisanan lan mung baris.

Ing versi string, kolom xmin diisi karo nomer transaksi saiki. Transaksi kasebut isih aktif, saengga bit xmin_committed lan xmin_aborted ora disetel.

Kolom ctid versi baris nuduhake baris sing padha. Iki tegese versi anyar ora ana.

Kolom xmax diisi karo angka goblok 0 amarga versi baris iki durung dibusak lan saiki. Transaksi ora bakal menehi perhatian marang nomer iki amarga bit xmax_aborted disetel.

Ayo njupuk langkah maneh kanggo nambah keterbacaan kanthi nambahake bit informasi menyang nomer transaksi. Lan ayo nggawe fungsi, amarga kita butuh panjaluk luwih saka sepisan:

=> CREATE FUNCTION heap_page(relname text, pageno integer)
RETURNS TABLE(ctid tid, state text, xmin text, xmax text, t_ctid tid)
AS $$
SELECT (pageno,lp)::text::tid AS ctid,
       CASE lp_flags
         WHEN 0 THEN 'unused'
         WHEN 1 THEN 'normal'
         WHEN 2 THEN 'redirect to '||lp_off
         WHEN 3 THEN 'dead'
       END AS state,
       t_xmin || CASE
         WHEN (t_infomask & 256) > 0 THEN ' (c)'
         WHEN (t_infomask & 512) > 0 THEN ' (a)'
         ELSE ''
       END AS xmin,
       t_xmax || CASE
         WHEN (t_infomask & 1024) > 0 THEN ' (c)'
         WHEN (t_infomask & 2048) > 0 THEN ' (a)'
         ELSE ''
       END AS xmax,
       t_ctid
FROM heap_page_items(get_raw_page(relname,pageno))
ORDER BY lp;
$$ LANGUAGE SQL;

Ing wangun iki, luwih cetha apa sing kedadeyan ing header versi baris:

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3664 | 0 (a) | (0,1)
(1 row)

Informasi sing padha, nanging kurang rinci, bisa dipikolehi saka tabel kasebut, nggunakake pseudo-columns xmin lan xmax:

=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3664 |    0 |  1 | FOO
(1 row)

Fiksasi

Yen transaksi kasil rampung, sampeyan kudu ngelingi statuse - elinga yen wis setya. Kanggo nindakake iki, struktur sing diarani XACT digunakake (lan sadurunge versi 10 diarani CLOG (komit log) lan jeneng iki isih bisa ditemokake ing macem-macem panggonan).

XACT dudu tabel katalog sistem; iki file ing PGDATA / pg_xact direktori. Dheweke duwe rong bit sing dialokasikan kanggo saben transaksi: setya lan dibatalake - kaya ing header versi baris. Informasi iki dipérang dadi sawetara file mung kanggo penak; kita bakal bali menyang masalah iki nalika nimbang pembekuan. Lan nggarap file kasebut ditindakake saben kaca, kaya kabeh liyane.

Dadi, nalika transaksi ditindakake ing XACT, bit komitmen disetel kanggo transaksi iki. Lan iki kabeh sing kedadeyan nalika nindakake (sanajan kita durung ngomong babagan log pra-rekaman).

Nalika transaksi liyane ngakses kaca tabel sing lagi wae kita deleng, mesthine kudu mangsuli sawetara pitakon.

  1. Apa transaksi xmin wis rampung? Yen ora, versi string sing digawe kudu ora katon.
    Priksa iki ditindakake kanthi ndeleng struktur liyane, sing ana ing memori bareng saka conto kasebut lan diarani ProcArray. Isine dhaptar kabeh proses aktif, lan kanggo saben siji nomer transaksi saiki (aktif) dituduhake.
  2. Yen rampung, banjur kepiye - kanthi nindakake utawa mbatalake? Yen dibatalake, banjur versi baris uga ora katon.
    Iki persis apa XACT kanggo. Nanging, sanajan kaca pungkasan XACT disimpen ing buffer ing RAM, iku isih larang kanggo mriksa XACT saben wektu. Mulane, yen status transaksi ditemtokake, ditulis menyang bit xmin_committed lan xmin_aborted saka versi string. Yen salah siji saka bit iki disetel, negara transaksi xmin dianggep dikenal lan transaksi sabanjuré ora kudu ngakses XACT.

Apa ora bit iki disetel dening transaksi dhewe nindakake insert? Nalika ana sisipan, transaksi durung ngerti apa bakal sukses. Lan nalika nindakake, ora jelas maneh baris endi kaca sing diganti. Bisa uga ana akeh kaca sing kaya ngono, lan ngeling-eling ora nguntungake. Kajaba iku, sawetara kaca bisa digusur saka cache buffer menyang disk; maca maneh kanggo ngganti bit bakal alon mudhun tundhuk Ngartekno.

Kakurangan saka tabungan yaiku sawise owah-owahan, transaksi apa wae (malah sing maca prasaja - PILIH) bisa miwiti ngganti kaca data ing cache buffer.

Dadi, ayo ndandani owah-owahan kasebut.

=> COMMIT;

Ora ana sing diganti ing kaca kasebut (nanging kita ngerti yen status transaksi wis dicathet ing XACT):

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3664 | 0 (a) | (0,1)
(1 row)

Saiki transaksi sing ngakses kaca pisanan kudu nemtokake status transaksi xmin lan nulis menyang bit informasi:

=> SELECT * FROM t;
 id |  s  
----+-----
  1 | FOO
(1 row)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3664 (c) | 0 (a) | (0,1)
(1 row)

Pambusakan

Nalika baris dibusak, nomer transaksi mbusak saiki ditulis ing lapangan xmax versi saiki, lan bit xmax_aborted wis dibusak.

Elinga yen nilai set xmax sing cocog karo transaksi aktif tumindak minangka kunci baris. Yen transaksi liyane pengin nganyari utawa mbusak baris iki, bakal dipeksa ngenteni transaksi xmax rampung. Kita bakal ngomong luwih akeh babagan pamblokiran mengko. Saiki, kita mung nyathet yen jumlah kunci baris ora ana watesan. Padha ora njupuk munggah spasi ing RAM lan kinerja sistem ora nandhang sangsara marga saka nomer. Bener, transaksi "dawa" duwe kekurangan liyane, nanging luwih akeh mengko.

Ayo mbusak baris.

=> BEGIN;
=> DELETE FROM t;
=> SELECT txid_current();
 txid_current 
--------------
         3665
(1 row)

Kita weruh yen nomer transaksi ditulis ing kolom xmax, nanging bit informasi ora disetel:

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax | t_ctid 
-------+--------+----------+------+--------
 (0,1) | normal | 3664 (c) | 3665 | (0,1)
(1 row)

pembatalan

Aborting owah-owahan dianggo padha kanggo nindakake, mung ing XACT dicokot aborted disetel kanggo transaksi. Undoing minangka cepet minangka laku. Sanajan printah kasebut diarani ROLLBACK, owah-owahan ora digulung maneh: kabeh sing bisa diganti transaksi ing kaca data tetep ora owah.

=> ROLLBACK;
=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax | t_ctid 
-------+--------+----------+------+--------
 (0,1) | normal | 3664 (c) | 3665 | (0,1)
(1 row)

Nalika kaca diakses, status bakal dicenthang lan bit petunjuk xmax_aborted bakal disetel menyang versi baris. Nomer xmax dhewe tetep ana ing kaca kasebut, nanging ora ana sing bakal ndeleng.

=> SELECT * FROM t;
 id |  s  
----+-----
  1 | FOO
(1 row)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   |   xmax   | t_ctid 
-------+--------+----------+----------+--------
 (0,1) | normal | 3664 (c) | 3665 (a) | (0,1)
(1 row)

Update

Nganyari dianggo kaya-kaya mbusak versi baris sing saiki lan banjur nglebokake sing anyar.

=> BEGIN;
=> UPDATE t SET s = 'BAR';
=> SELECT txid_current();
 txid_current 
--------------
         3666
(1 row)

Pitakonan ngasilake siji baris (versi anyar):

=> SELECT * FROM t;
 id |  s  
----+-----
  1 | BAR
(1 row)

Nanging ing kaca kita ndeleng loro versi:

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3664 (c) | 3666  | (0,2)
 (0,2) | normal | 3666     | 0 (a) | (0,2)
(2 rows)

Versi sing wis dibusak ditandhani karo nomer transaksi saiki ing lapangan xmax. Kajaba iku, nilai iki ditulis liwat sing lawas, amarga transaksi sadurunge dibatalake. Lan bit xmax_aborted wis dibusak amarga status transaksi saiki durung dikenal.

Versi pisanan baris saiki nuduhake nomer loro (bidang t_ctid) minangka sing luwih anyar.

Indeks kapindho katon ing kaca indeks lan baris kapindho ngrujuk versi kapindho ing kaca tabel.

Kaya dene pambusakan, nilai xmax ing versi pisanan baris kasebut minangka indikasi yen baris kasebut dikunci.

Inggih, ayo ngrampungake transaksi.

=> COMMIT;

Indeks

Nganti saiki, kita mung ngomong babagan kaca tabel. Apa sing kedadeyan ing indeks kasebut?

Informasi ing kaca indeks beda-beda gumantung saka jinis indeks tartamtu. Lan malah siji jinis indeks duwe macem-macem jinis kaca. Contone, wit B duwe kaca metadata lan kaca "biasa".

Nanging, kaca biasane duwe macem-macem penunjuk menyang larik lan larik dhewe (kaya kaca tabel). Kajaba iku, ing pungkasan kaca ana papan kanggo data khusus.

Baris ing indeks uga bisa duwe struktur sing beda banget gumantung saka jinis indeks. Contone, kanggo wit-B, baris sing ana gandhengane karo kaca godhong ngemot nilai kunci indeksasi lan referensi (ctid) menyang baris tabel sing cocog. Umumé, indeks bisa disusun kanthi cara sing beda.

Titik sing paling penting yaiku ora ana versi baris ing indeks apa wae. Inggih, utawa kita bisa nganggep yen saben baris diwakili persis siji versi. Ing tembung liyane, ora ana kolom xmin lan xmax ing header baris indeks. Kita bisa nganggep manawa pranala saka indeks mimpin menyang kabeh versi tabel baris - supaya sampeyan bisa nemtokake versi sing bakal dideleng transaksi mung kanthi ndeleng tabel. (Minangka biasane, iki ora kabeh bebener. Ing sawetara kasus, peta visibilitas bisa ngoptimalake proses kasebut, nanging kita bakal nliti iki kanthi luwih rinci mengko.)

Ing wektu sing padha, ing kaca indeks kita nemokake pitunjuk kanggo loro versi, sing saiki lan sing lawas:

=> SELECT itemoffset, ctid FROM bt_page_items('t_s_idx',1);
 itemoffset | ctid  
------------+-------
          1 | (0,2)
          2 | (0,1)
(2 rows)

Transaksi virtual

Ing praktik, PostgreSQL nggunakake optimasi sing ngidini "nyimpen" nomer transaksi.

Yen transaksi mung maca data, ora ana pengaruh ing visibilitas versi baris. Mulane, proses layanan pisanan ngetokake xid virtual kanggo transaksi kasebut. Nomer kasebut kalebu ID proses lan nomer urutan.

Nerbitake nomer iki ora mbutuhake sinkronisasi antarane kabeh proses lan mulane cepet banget. Kita bakal kenal karo alasan liyane kanggo nggunakake nomer virtual nalika kita ngomong babagan pembekuan.

Nomer virtual ora dianggep kanthi cara apa wae ing jepretan data.

Ing wektu sing beda-beda, bisa uga ana transaksi virtual ing sistem kanthi nomer sing wis digunakake, lan iki normal. Nanging angka kasebut ora bisa ditulis ing kaca data, amarga sabanjure kaca kasebut bisa diakses, bisa uga ilang kabeh makna.

=> BEGIN;
=> SELECT txid_current_if_assigned();
 txid_current_if_assigned 
--------------------------
                         
(1 row)

Yen transaksi wiwit ngganti data, iku diwenehi nyata, nomer transaksi unik.

=> UPDATE accounts SET amount = amount - 1.00;
=> SELECT txid_current_if_assigned();
 txid_current_if_assigned 
--------------------------
                     3667
(1 row)

=> COMMIT;

Transaksi Nested

Simpen poin

Ditetepake ing SQL nyimpen TCTerms (savepoint), sing ngidini sampeyan mbatalake bagean saka transaksi tanpa ngganggu kabeh. Nanging iki ora pas menyang diagram ndhuwur, wiwit transaksi wis status padha kanggo kabeh owah-owahan, lan fisik ora ana data mbalek maneh.

Kanggo ngleksanakake fungsi iki, transaksi karo titik nyimpen dipérang dadi sawetara kapisah transaksi nested (subtransaksi), statuse bisa diatur kanthi kapisah.

Transaksi bersarang duwe nomer dhewe (luwih dhuwur tinimbang jumlah transaksi utama). Status transaksi nested direkam ing cara biasanipun ing XACT, nanging status final gumantung ing status transaksi utama: yen dibatalake, banjur kabeh transaksi nested uga dibatalake.

Informasi babagan nesting transaksi disimpen ing file ing direktori PGDATA/pg_subtrans. File diakses liwat buffer ing memori bareng instance, diatur ing cara sing padha XACT buffer.

Aja bingung transaksi nested karo transaksi otonom. Transaksi otonom ora gumantung ing saben liyane, nanging transaksi nested. Ora ana transaksi otonom ing PostgreSQL biasa, lan, bisa uga, sing paling apik: dibutuhake banget, arang banget, lan anane ing DBMS liyane nyebabake penyalahgunaan, mula saben wong nandhang lara.

Ayo mbusak tabel, miwiti transaksi lan lebokake baris:

=> TRUNCATE TABLE t;
=> BEGIN;
=> INSERT INTO t(s) VALUES ('FOO');
=> SELECT txid_current();
 txid_current 
--------------
         3669
(1 row)

=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
(1 row)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3669 | 0 (a) | (0,1)
(1 row)

Saiki ayo sijine titik nyimpen lan lebokake baris liyane.

=> SAVEPOINT sp;
=> INSERT INTO t(s) VALUES ('XYZ');
=> SELECT txid_current();
 txid_current 
--------------
         3669
(1 row)

Elinga yen fungsi txid_current () ngasilake nomer transaksi utama, ora nomer transaksi nested.

=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
 3670 |    0 |  3 | XYZ
(2 rows)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3669 | 0 (a) | (0,1)
 (0,2) | normal | 3670 | 0 (a) | (0,2)
(2 rows)

Ayo bali menyang titik nyimpen lan lebokake baris katelu.

=> ROLLBACK TO sp;
=> INSERT INTO t(s) VALUES ('BAR');
=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
 3671 |    0 |  4 | BAR
(2 rows)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3669     | 0 (a) | (0,1)
 (0,2) | normal | 3670 (a) | 0 (a) | (0,2)
 (0,3) | normal | 3671     | 0 (a) | (0,3)
(3 rows)

Ing kaca kita terus ndeleng baris ditambahake dening transaksi nested dibatalake.

Kita ndandani owah-owahan.

=> COMMIT;
=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
 3671 |    0 |  4 | BAR
(2 rows)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3669 (c) | 0 (a) | (0,1)
 (0,2) | normal | 3670 (a) | 0 (a) | (0,2)
 (0,3) | normal | 3671 (c) | 0 (a) | (0,3)
(3 rows)

Saiki sampeyan bisa ndeleng kanthi jelas manawa saben transaksi nested duwe status dhewe.

Elinga yen transaksi bersarang ora bisa digunakake sacara eksplisit ing SQL, yaiku, sampeyan ora bisa miwiti transaksi anyar tanpa ngrampungake transaksi saiki. Mekanisme iki diaktifake sacara implisit nalika nggunakake titik nyimpen, uga nalika nangani pengecualian PL/pgSQL lan ing sawetara kasus liyane sing luwih endah.

=> BEGIN;
BEGIN
=> BEGIN;
WARNING:  there is already a transaction in progress
BEGIN
=> COMMIT;
COMMIT
=> COMMIT;
WARNING:  there is no transaction in progress
COMMIT

Kasalahan lan atomicity saka operasi

Apa sing kedadeyan yen ana kesalahan nalika nindakake operasi? Contone, kaya iki:

=> BEGIN;
=> SELECT * FROM t;
 id |  s  
----+-----
  2 | FOO
  4 | BAR
(2 rows)

=> UPDATE t SET s = repeat('X', 1/(id-4));
ERROR:  division by zero

Ana kesalahan. Saiki transaksi kasebut dianggep batal lan ora ana operasi sing diidini:

=> SELECT * FROM t;
ERROR:  current transaction is aborted, commands ignored until end of transaction block

Lan sanajan sampeyan nyoba nindakake owah-owahan, PostgreSQL bakal nglaporake batal:

=> COMMIT;
ROLLBACK

Napa transaksi ora bisa dilanjutake sawise gagal? Kasunyatan iku kesalahan bisa njedhul ing kuwi cara sing kita bakal entuk akses menyang bagean saka owah-owahan - atomicity malah ora transaksi, nanging operator bakal nerak. Kaya ing conto, ing ngendi operator bisa nganyari siji baris sadurunge kesalahan:

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3669 (c) | 3672  | (0,4)
 (0,2) | normal | 3670 (a) | 0 (a) | (0,2)
 (0,3) | normal | 3671 (c) | 0 (a) | (0,3)
 (0,4) | normal | 3672     | 0 (a) | (0,4)
(4 rows)

Sampeyan kudu ngomong yen psql duwe mode sing isih ngidini transaksi diterusake sawise gagal kaya-kaya tumindak operator sing salah digulung maneh.

=> set ON_ERROR_ROLLBACK on
=> BEGIN;
=> SELECT * FROM t;
 id |  s  
----+-----
  2 | FOO
  4 | BAR
(2 rows)

=> UPDATE t SET s = repeat('X', 1/(id-4));
ERROR:  division by zero

=> SELECT * FROM t;
 id |  s  
----+-----
  2 | FOO
  4 | BAR
(2 rows)

=> COMMIT;

Ora angel ditebak manawa ing mode iki, psql bener-bener nempatake titik simpen sing implisit sadurunge saben printah, lan yen gagal miwiti rollback. Mode iki ora digunakake minangka standar, amarga nyetel titik nyimpen (sanajan tanpa muter maneh) kalebu overhead sing signifikan.

Terusane.

Source: www.habr.com

Add a comment