ปิดใช้งานคอมมิชชันที่ชัดเจนใน JDBC ตรวจจับใน SQL หรือทำให้ฐานข้อมูลอยู่ในสถานะอ่านอย่างเดียว


12

พื้นหลัง : ฉันกำลังทำงานในhttp://sqlfiddle.com (เว็บไซต์ของฉัน) และกำลังพยายามป้องกันไม่ให้มีการละเมิดวิธีใดวิธีหนึ่ง ฉันหวังว่าด้วยการถามเกี่ยวกับปัญหาที่ฉันกำลังพูดถึงอยู่ในปัจจุบันฉันไม่ได้ตั้งใจทำให้การละเมิดที่อาจเกิดขึ้นแย่ลงโดยไม่ได้ตั้งใจ แต่คุณจะทำอย่างไร ฉันเชื่อใจพวกคุณ

ฉันต้องการป้องกันไม่ให้ผู้ใช้ออกการเรียก 'ส่งสัญญาณ' อย่างชัดเจนภายในบล็อคธุรกรรม จากบริบทของ SQL Fiddle บล็อกธุรกรรมคือรหัสที่เรียกใช้งานบนแผงด้านขวา โดยทั่วไปฉันจะวนซ้ำและดำเนินการรายการคำสั่ง plaintext SQL และฉันต้องการให้แน่ใจว่าการเปลี่ยนแปลงทั้งหมดที่ทำจะถูกย้อนกลับในตอนท้ายของแบทช์ โดยปกติการเปลี่ยนแปลงของพวกเขาจะได้รับการย้อนกลับ แต่บางครั้งก็มีคำสั่ง 'กระทำ' ที่ชัดเจนภายในข้อความและแน่นอนว่าการย้อนกลับของฉันจะไม่ทำงาน ความมุ่งมั่นที่ชัดเจนนี้มีแนวโน้มมากจากผู้ใช้ที่พยายามจะทำลาย schema บน SQL Fiddle ดังนั้นคนอื่น ๆ ที่ทำงานกับมันจะเห็นข้อผิดพลาด

ผลลัพธ์หลักที่ต้องการ : ฉันต้องการปิดใช้งานการกระทำที่ชัดเจนในระดับ JDBC ถ้าเป็นไปได้ นี่เป็นเพราะฉันต้องสนับสนุนผู้ขายแบ็กเอนด์ฐานข้อมูลหลายคนและแน่นอนว่าแต่ละคนมีนิสัยใจคอในระดับต่ำ

ตัวเลือกสำรอง : หากไม่สามารถกำหนดค่า JDBC เพื่อปิดใช้งานการกระทำที่ชัดเจนได้ฉันจะเปิดให้มีการตรวจหาการกระทำที่ชัดเจนในขณะประมวลผลชุดข้อมูลสำหรับแบ็กเอนด์ต่อไปนี้: SQL Server, Oracle, MySQL และ PostgreSQL

สำหรับ SQL Server ฉันคิดถึงวิธีนี้: แยกวิเคราะห์แผนการสืบค้น XML สำหรับคำสั่งก่อนที่ฉันจะดำเนินการและตรวจสอบการมีอยู่ของรายการที่ตรงกับ XPath นี้:

//*[@StatementType="COMMIT TRANSACTION"]

ฉันคิดว่านี่จะทำงานได้ดีสำหรับ SQL Server อย่างไรก็ตามวิธีนี้ใช้ไม่ได้กับฐานข้อมูลประเภทอื่น เอาต์พุตแผนการดำเนินการ XML ของ Oracle สำหรับการส่งข้อมูลที่ชัดเจนไม่ได้อ้างอิงถึงข้อเท็จจริงที่ว่าคุณกำลังเรียกใช้คำสั่ง commit (แต่เพียงทำซ้ำเอาต์พุตแผนการดำเนินการจากเคียวรีที่คอมมิท) PostgreSQL และ MySQL ไม่ได้เตรียมเอาท์พุทแผนการดำเนินการใด ๆ เลย (XML หรืออย่างอื่น) สำหรับการกระทำที่ชัดเจน

ทำให้ฉันตรวจสอบคำสั่งจริงสำหรับคำว่า "commit" สิ่งนี้จะได้ผลเว้นแต่มีความผันแปรได้ทุกประเภท:

declare @sql varchar(50)
set @sql = 'com' + 'mit'
exec(@sql);

ด้านบนเป็นตัวอย่างสำหรับ SQL Server (ซึ่งฉันสามารถแก้ไขได้) แต่ฉันเดาว่าสิ่งที่คล้ายกันอาจเป็นไปได้สำหรับ Oracle, MySQL และ PostgreSQL ฉันคิดผิดไปหรือเปล่า พวกเขาอาจจะไม่อนุญาตให้ใช้คำสั่ง "แบบไดนามิก"? อย่าลังเลที่จะใช้ SQL Fiddle (โดยเฉพาะอย่างยิ่งไม่ใช่ schema ตัวอย่างหรือมีคนอื่นกำลังทำงานอยู่) เพื่อดูว่าคุณสามารถทำสิ่งที่คล้ายกันเกิดขึ้นใน Oracle, MySQL และ PostgreSQL ได้ไหม ถ้าไม่เช่นนั้นการตรวจจับสตริงอย่างง่ายอาจใช้ได้ผล

ความเป็นไปได้อีกอย่างหนึ่ง

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

ปรับปรุง

สิ่งที่ฉันเรียนรู้เมื่อเร็ว ๆ นี้ - จริง ๆ แล้วไม่มีปัญหากับ PostgreSQL เห็นได้ชัดว่าการกระทำที่ออกภายในบล็อกธุรกรรมจะไม่นำไปใช้หากในที่สุดบล็อกเดียวกันนั้นได้รับการย้อนกลับ (ใน Postgres) ดังนั้นไชโยสำหรับ Postgres!

ขอบคุณลิงก์ของ Phil ไปยังโพสต์ SO ฉันคิดว่าฉันสามารถใช้แฮ็ค DEFERRABLE INFIEDY DEFERRED ที่ถูกกำหนดไว้ล่วงหน้าเพื่อให้ Oracle บรรลุสิ่งที่ฉันต้องการ สิ่งนี้ควรระบุถึง Oracle (ฉันคิดว่าชั่วขณะหนึ่งที่ธุรกรรมซ้อนกันอาจทำงานที่นี่ แต่ดูเหมือนว่า Oracle ไม่รองรับธุรกรรมซ้อนกันหรือไม่ฉันไม่สามารถหาสิ่งที่ใช้วิธีนี้ได้)

ยังไม่มีทางออกสำหรับ MySQL จริงๆ พยายามใช้การทำธุรกรรมที่ซ้อนกัน แต่ไม่ได้ผล ฉันคิดอย่างจริงจังถึงวิธีการที่รุนแรงมากขึ้นสำหรับ MySQL เช่นอาจไม่อนุญาตอะไรเลยนอกจากการเลือกทางด้านขวาหรือการวาง / สร้างฐานข้อมูลซ้ำหลังการสืบค้นแต่ละครั้ง ไม่ว่าจะฟังดูดี

มติ

ดังนั้นตอนนี้ฉันได้ติดตั้งโซลูชันที่อธิบายไว้สำหรับ SQL Server และ Oracle และตามที่ฉันกล่าวถึงสิ่งนี้ไม่ใช่ปัญหาสำหรับ PostgreSQL สำหรับ MySQL ฉันใช้ขั้นตอนที่ค่อนข้างโชคร้ายในการ จำกัด แผงการสืบค้นเพื่อเลือกเฉพาะข้อความสั่ง DDL และ DML สำหรับ MySQL จะต้องป้อนในแผงสคีมา (ด้านซ้าย) ฉันหวังว่านี่จะไม่ทำลายซอเก่า ๆ จำนวนมากเกินไป แต่ฉันคิดว่ามันเป็นสิ่งที่ต้องทำเพื่อให้แน่ใจว่าข้อมูลมีความสอดคล้องกัน ขอบคุณ!


ควรค่าแก่การกล่าวถึง - ฉันได้ทำการค้นคว้าจำนวนมากเพื่อค้นหาทริกเกอร์ "pre-commit" ดูเหมือนว่าไม่มีอยู่ดังนั้นน่าเสียดายที่ไม่มีตัวเลือกเช่นกัน
Jake Feasel

2
สำหรับ Oracle สิ่งนี้ดูเหมือนจะเป็นวิธีที่ดีในการจับ COMMITs: stackoverflow.com/a/6463800/790702สิ่งที่เขาไม่ได้กล่าวถึงก็คือคุณควรจะสามารถจับการละเมิดข้อ จำกัด ในโค้ดของคุณได้เช่นกันเพื่อหยุดสถานการณ์ที่ 2 ที่เกิดขึ้น
Philᵀᴹ

@ เฉพาะปัญหาเดียวที่ฉันไม่ได้มี (และไม่ต้องการ) ควบคุมนิยามของแต่ละตาราง (ที่ถูกกำหนดไว้ที่แผงด้านซ้าย) เพื่อให้เป็นไปตามข้อ DEFERRABLE รอการตัดบัญชีขั้นแรกจะไม่ได้อยู่ที่นั่น (เว้นแต่จะมีวิธีการบางอย่างที่จะทำโดยอัตโนมัติสำหรับตารางทั้งหมด? - พูดผ่านทริกเกอร์ระบบที่ตอบสนองต่อการสร้างงบตารางฮึ)
เจค Feasel

1
@NickChammas ฉันต้องปิดการใช้งานเพื่อให้ฉันสามารถเก็บ schema (ตามที่กำหนดโดยแผงด้านซ้าย) ในสถานะคงที่ อาจมีคนจำนวนมากที่เขียนคิวรีกับสคีมาเดียวกันที่พยายามแก้ไขปัญหาเดียวกัน เพื่อป้องกันพวกเขาจากการรบกวนซึ่งกันและกันฉันต้องแน่ใจว่าได้ป้องกันโครงสร้างและข้อมูลจากการเปลี่ยนแปลง สิ่งนี้สามารถทำได้ผ่านการทำธุรกรรมย้อนกลับ แต่ไม่เกิดขึ้นหากมีการส่งมอบรหัสด้านขวา
Jake Feasel

2
@RickJames DDL สร้างการกระทำโดยนัยใน MySQL และ Oracle แต่ไม่ใช่ใน PostgreSQL หรือ SQL Server กลไกที่ฉันนำมาใช้ในการจัดการกับโพสต์นี้เกี่ยวข้อง เท่าที่ป้อน SQL โดยพลการ - นั่นคือประเด็นทั้งหมด!
Jake Feasel

คำตอบ:


3

สำหรับ Oracle สิ่งนี้ดูเหมือนจะเป็นวิธีการที่น่าจับตามองของ COMMIT:

/programming//a/6463800/790702

สิ่งที่เขาไม่ได้กล่าวถึงคือคุณควรจะสามารถจับการละเมิดข้อ จำกัด ในรหัสของคุณได้เช่นกันเพื่อหยุดสถานการณ์ที่ 2 ที่เกิดขึ้น


เยี่ยมมากขอบคุณอีกครั้ง Phil ฉันสามารถใช้เทคนิคนี้กับ Oracle ได้ดี มันทำให้ฉันหวังว่าฐานข้อมูลอื่น ๆ รองรับข้อ จำกัด รอการตัดบัญชี
Jake Feasel

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