PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

postgresql - लेन-देन ब्लॉक का उपयोग करने वाली स्क्रिप्ट सभी रिकॉर्ड बनाने में विफल रहती है

हां, आप कुछ गलत कर रहे हैं।
साधारण उदाहरण देखें।

सत्र 1

postgres=# select * from user_reservation_table;
 id | usedyesno | userid | uservalue
----+-----------+--------+-----------
  1 | f         |      0 |         1
  2 | f         |      0 |         2
  3 | f         |      0 |         3
  4 | f         |      0 |         4
  5 | f         |      0 |         5
(5 wierszy)


postgres=# \set user 1
postgres=#
postgres=# begin;
BEGIN
postgres=# UPDATE user_reservation_table
postgres-# SET UsedYesNo = true, userid=:user
postgres-# WHERE uservalue IN(
postgres(#    SELECT uservalue FROM user_reservation_table
postgres(#    WHERE UsedYesNo=false Order By id ASC Limit 1)
postgres-# RETURNING uservalue;
 uservalue
-----------
         1
(1 wiersz)


UPDATE 1
postgres=#


सत्र 2 - उसी समय, लेकिन केवल 10 एमएस बाद में

postgres=# \set user 2
postgres=# begin;
BEGIN
postgres=# UPDATE user_reservation_table
postgres-# SET UsedYesNo = true, userid=:user
postgres-# WHERE uservalue IN(
postgres(#    SELECT uservalue FROM user_reservation_table
postgres(#    WHERE UsedYesNo=false Order By id ASC Limit 1)
postgres-# RETURNING uservalue;

सत्र 2 रुका हुआ है ...... और किसी चीज़ की प्रतीक्षा कर रहा है ....

सत्र 1 में वापस

postgres=# commit;
COMMIT
postgres=#



और फिर सत्र 2

 uservalue
-----------
         1
(1 wiersz)


UPDATE 1
postgres=# commit;
COMMIT
postgres=#

सत्र 2 अब और प्रतीक्षा नहीं कर रहा है, और अपना लेन-देन पूरा कर चुका है।

और अंतिम परिणाम क्या है ?:

postgres=# select * from user_reservation_table order by id;
 id | usedyesno | userid | uservalue
----+-----------+--------+-----------
  1 | t         |      2 |         1
  2 | f         |      0 |         2
  3 | f         |      0 |         3
  4 | f         |      0 |         4
  5 | f         |      0 |         5
(5 wierszy)

दो उपयोगकर्ताओं ने समान मान 1 लिया, लेकिन तालिका में केवल उपयोगकर्ता 2 पंजीकृत है




====================संपादित करें ================================

इस परिदृश्य में हम SELECT .. FOR UPDATE का उपयोग कर सकते हैं और उस तरीके का उपयोग कर सकते हैं जिसमें पोस्टग्रे रीड कमिटेड आइसोलेशन लेवल मोड में क्वेरी का पुनर्मूल्यांकन करता है,
दस्तावेज़ देखें:http://www.postgresql.org/docs/9.2/static/transaction-iso.html

संक्षेप में:
यदि एक सत्र ने पंक्ति को लॉक कर दिया है, और दूसरा सत्र उसी पंक्ति को लॉक करने का प्रयास कर रहा है, तो दूसरा सत्र "हैंग" होगा और पहले सत्र के कमिट या रोलबैक होने की प्रतीक्षा करेगा। जब पहला सत्र लेन-देन करता है, तो दूसरा सत्र WHERE खोज स्थिति का पुनर्मूल्यांकन करेगा। यदि खोज की स्थिति मेल नहीं खाती है (क्योंकि पहले लेन-देन ने कुछ कॉलम बदल दिए हैं), तो दूसरा सत्र उस पंक्ति को छोड़ देगा, और अगली पंक्ति को संसाधित करेगा जो WHERE से मेल खाती है शर्तें।

नोट:रिपीटेबल रीड आइसोलेशन लेवल में यह व्यवहार अलग है। उस स्थिति में दूसरा सत्र त्रुटि देगा:समवर्ती अपडेट के कारण एक्सेस को क्रमबद्ध नहीं कर सका, और आपको पूरे लेनदेन को फिर से करना होगा।

हमारी क्वेरी हो सकती है इस तरह दिखें:

select id from user_reservation_table
where usedyesno = false
order by id
limit 1
for update ;

और फिर:

  Update .... where id = (id returned by SELECT ... FOR UPDATE)



व्यक्तिगत रूप से, मैं सादे, पुराने कंसोल क्लाइंट (पोस्टग्री के लिए psql, oracle के लिए mysql या SQLPlus) का उपयोग करके लॉकिंग परिदृश्य का परीक्षण करना पसंद करता हूं

तो psql में हमारी क्वेरी का परीक्षण करें:

session1 #select * from user_reservation_table order by id;
 id | usedyesno | userid | uservalue
----+-----------+--------+-----------
  1 | t         |      2 |         1
  2 | f         |      0 |         2
  3 | f         |      0 |         3
  4 | f         |      0 |         4
  5 | f         |      0 |         5
(5 wierszy)


session1 #begin;
BEGIN
session1 #select id from user_reservation_table
postgres-# where usedyesno = false
postgres-# order by id
postgres-# limit 1
postgres-# for update ;
 id
----
  2
(1 wiersz)


session1 #update user_reservation_table set usedyesno = true
postgres-# where id = 2;
UPDATE 1
session1 #

सत्र 1 लॉक किया गया और एक पंक्ति id=2 अपडेट की गई

और अब सत्र2

session2 #begin;
BEGIN
session2 #select id from user_reservation_table
postgres-# where usedyesno = false
postgres-# order by id
postgres-# limit 1
postgres-# for update ;

पंक्ति आईडी को लॉक करने का प्रयास करते समय सत्र 2 रुक जाता है =2

ठीक है, सत्र 1 को प्रतिबद्ध होने दें

session1 #commit;
COMMIT
session1 #

और देखें कि सत्र 2 में क्या होता है:

अपडेट के लिए
postgres-# for update ;
 id
----
  3
(1 wiersz)

बिंगो - सत्र 2 ने पंक्ति आईडी =2 को छोड़ दिया और पंक्ति आईडी =3 का चयन (और लॉक) किया


तो हमारी अंतिम क्वेरी हो सकती है:

update user_reservation_table
set usedyesno = true
where id = (
   select id from user_reservation_table
   where usedyesno = false
   order by id
   limit 1
   for update
) RETURNING uservalue;

कुछ आरक्षण - यह उदाहरण केवल आपके परीक्षण के उद्देश्य के लिए है और इसका उद्देश्य यह समझने में मदद करना है कि पोस्टग्रे में लॉकिंग कैसे काम कर रहा है।
वास्तव में, यह क्वेरी तालिका तक पहुंच को क्रमबद्ध करेगी, और स्केलेबल नहीं है और शायद प्रदर्शन करेगी बहुउपयोगकर्ता वातावरण में खराब (धीमा)। उत्पादन कोड में यह प्रश्न।
क्या आप वाकई "तालिका से अगला मान ढूंढना और आरक्षित करना चाहते हैं"? क्यों ?
यदि हाँ, तो आपके पास कुछ क्रमांकन उपकरण होना चाहिए (जैसे कि यह क्वेरी, या शायद लागू करने में आसान, पूरी तालिका को लॉक करना), लेकिन यह एक अड़चन होगी।




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. INSERT / UPDATE / DELETE ऑपरेशन को ऑप्टिमाइज़ करें

  2. रेल 3.1। Heroku PGError:ऑपरेटर मौजूद नहीं है:वर्ण भिन्न =पूर्णांक

  3. पोस्टग्रेज में कुछ को छोड़कर सभी डेटाबेस कैसे छोड़ें?

  4. कैसे psql के भीतर से एक postgresql डेटाबेस का बैकअप लेने के लिए?

  5. OSX Lion पर PostgreSQL 9.1 कैसे स्थापित करें