ธุรกรรมใน PostgreSQL ผ่านทาง `psycopg2` ต่อเคอร์เซอร์หรือต่อการเชื่อมต่อหรือไม่?


10

ฉันทำงานกับ PostgreSQL 9.3 โดยใช้psycopg2API ฐานข้อมูล

ฉันได้ตั้งค่า API API ในระดับการแยกขั้นต่ำ (โหมด "autocommit") และกำลังจัดการธุรกรรมของฉันเองโดยตรงผ่าน SQL ตัวอย่าง:

cur = self.conn.cursor()
cur.execute("BEGIN;")
cur.execute("SELECT dbId, downloadPath, fileName, tags FROM {tableName} WHERE dlState=%s".format(tableName=self.tableName), (2, ))
ret = cur.fetchall()
cur.execute("COMMIT;")

โดยพื้นฐานแล้วธุรกรรมที่เริ่มต้นด้วยการcur.execute("BEGIN;")จำกัด เพียงเคอร์เซอร์นั้นหรือสำหรับการเชื่อมต่อทั้งหมด ( self.conn.cursor())?

สิ่งที่ซับซ้อนยิ่งกว่าที่ฉันกำลังทำอยู่นั้นเกี่ยวข้องกับการดำเนินการฐานข้อมูลแยกกันหลายครั้ง เนื่องจากทั้งหมดนี้อยู่ในคลาสที่มีการเชื่อมต่อเป็นสมาชิกจึงสะดวกยิ่งขึ้นในการสร้างเคอร์เซอร์ภายในแต่ละฟังก์ชั่น อย่างไรก็ตามฉันไม่แน่ใจว่าการสร้างเคอร์เซอร์ภายในธุรกรรมได้อย่างไร

โดยพื้นฐานแล้วถ้าธุรกรรมต่อการเชื่อมต่อฉันสามารถสร้างเคอร์เซอร์จำนวนมากได้ทันทีภายในธุรกรรม หากพวกเขาต่อเคอร์เซอร์นั่นหมายความว่าฉันต้องผ่านเคอร์เซอร์ไปทุกที่ มันคืออะไร

เอกสารไม่ได้สัมผัสกับสิ่งนี้แม้ว่าความจริงที่ว่าคุณสามารถโทรได้connection.commit()ทำให้ฉันมั่นใจอย่างเป็นธรรมว่าการควบคุมการทำธุรกรรมนั้นเป็นการเชื่อมต่อ

คำตอบ:


7

ธุรกรรมต่อเซสชันคือต่อการเชื่อมต่อ

PostgreSQL ไม่สนับสนุนการระงับและการทำธุรกรรมต่อดังนั้น psycopg2 จึงไม่สามารถสร้างมันต่อเคอร์เซอร์เว้นแต่ว่ามันจะสร้างการเชื่อมต่อใหม่ที่อยู่เบื้องหลัง

ในทางปฏิบัติฉันไม่พบเคอร์เซอร์ของ psycopg2 ที่มีประโยชน์เป็นพิเศษ พวกเขาสามารถเก็บชุดผลลัพธ์ไว้ได้หากคุณไม่ได้ใช้การดึงข้อมูลที่เพิ่มขึ้นจากเซิร์ฟเวอร์ แต่ฉันคิดว่ามันไม่ดีเท่าไร

ทำไมถึงออกด้วยตนเองbeginและcommitแม้ว่าแทนที่จะใช้วิธีการเชื่อมต่อสำหรับพวกเขา?


AFICT จากเอกสารประกอบโมเดล "DB API" ทั้งหมดไม่สนับสนุนการทำธุรกรรมอย่างชัดเจนเลย
ชื่อปลอม

1
@FakeName beginคุณไม่ได้อย่างชัดเจน หากไม่มีการทำธุรกรรมใด ๆ เปิดใหม่จะเริ่มต้นขึ้นสำหรับคุณ คุณเพียงcommitเพื่อแยกธุรกรรม ดังนั้นใช่รุ่น DB-API ไม่สนับสนุนการทำธุรกรรมอย่างชัดเจน
Craig Ringer

1
ถ้า DB api กำลังทำมันโดยอัตโนมัติโดยที่ฉันไม่ได้บอกให้ทำอย่างนั้นเป็นการเริ่มต้นโดยนัย และนอกจากนี้มันไม่เกี่ยวข้องเนื่องจาก (ตามที่ฉันระบุในคำถาม) ฉันใช้โหมด autocommit เพราะฉันไม่ต้องการBEGINข้อความอัตโนมัติเหล่านั้น ฉันไม่ต้องการpsycopg2สร้างธุรกรรมใหม่สำหรับแต่ละSELECTรายการ
ชื่อปลอม

TL; DR โดยทั่วไปฉันต้องการทราบขอบเขตที่แน่นอนของการทำธุรกรรมทั้งหมดที่เกิดขึ้นเพราะ A. ฉันคลั่งไปในทางนั้นและ B. มันช่วยได้มากในการดีบัก
ชื่อปลอม

1
ฉันไม่แปลกใจที่เห็นข้อบกพร่องแปลก ๆ โผล่ขึ้นมาด้วยสิ่งนี้ AFAIK autocommit นั้นมีความหมายว่าautocommitไม่ใช่การทำธุรกรรมแบบแมนนวล ถ้าคุณอยากที่จะจัดการขอบเขตการทำธุรกรรมด้วยตนเองเป็นพิเศษBEGINไม่เป็นอันตรายและจะเพิ่งจะปฏิเสธโดย PostgreSQL WARNING: there is already a transaction in progressกับ
Craig Ringer

1

จากเอกสารpsycopg2 :

ในธุรกรรม Psycopg ได้รับการจัดการโดยคลาสการเชื่อมต่อ โดยค่าเริ่มต้นครั้งแรกที่คำสั่งถูกส่งไปยังฐานข้อมูล (โดยใช้หนึ่งในเคอร์เซอร์ที่สร้างขึ้นโดยการเชื่อมต่อ) ธุรกรรมใหม่จะถูกสร้างขึ้น คำสั่งฐานข้อมูลต่อไปนี้จะถูกดำเนินการในบริบทของการทำธุรกรรมเดียวกัน - ไม่เพียง แต่คำสั่งที่ออกโดยเคอร์เซอร์แรก แต่คำสั่งที่ออกโดยเคอร์เซอร์ทั้งหมดที่สร้างขึ้นโดยการเชื่อมต่อเดียวกัน หากคำสั่งใด ๆ ล้มเหลวการทำธุรกรรมจะถูกยกเลิกและจะไม่มีการดำเนินการคำสั่งเพิ่มเติมจนกว่าจะมีการเรียกไปยังวิธีการย้อนกลับ ()

ในเวลาเดียวกันจากรุ่น 2.4.2 มีautocommitแอตทริบิวต์ (เน้นเพิ่ม):

อ่าน / เขียนคุณสมบัติ: ถ้าTrueไม่มีการจัดการธุรกรรมโดยไดรเวอร์และทุกคำสั่งที่ส่งไปยังส่วนหลังมีผลทันที หากFalse การทำธุรกรรมใหม่เริ่มต้นที่การดำเนินการคำสั่งแรก : วิธีการcommit()หรือrollback()จะต้องเรียกใช้ด้วยตนเองเพื่อยุติการทำธุรกรรม

โหมด autocommit จะเป็นประโยชน์ในการดำเนินการคำสั่งที่กำหนดที่จะทำงานนอกทำธุรกรรมเช่นหรือCREATE DATABASEVACUUM

ค่าเริ่มต้นคือFalse(กระทำด้วยตนเอง) ตามข้อกำหนด DBAPI

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.