Nonaktifkan komit eksplisit di JDBC, deteksi mereka dalam SQL, atau letakkan database dalam status readonly

12

Latar Belakang : Saya sedang mengerjakan http://sqlfiddle.com (situs saya), dan saya mencoba untuk mencegah kemungkinan penyalahgunaan. Saya berharap bahwa dengan menanyakan masalah yang sedang saya tangani saat ini, saya tidak secara tidak sengaja memperburuk potensi penyalahgunaan, tetapi apa yang dapat Anda lakukan? Aku percaya kalian

Saya ingin mencegah pengguna mana pun mengeluarkan panggilan 'komit' eksplisit dalam blok transaksi yang diberikan. Dari konteks SQL Fiddle, blok transaksi adalah kode yang dieksekusi pada panel sisi kanan. Pada dasarnya, saya mengulang dan menjalankan daftar perintah SQL plaintext, dan saya ingin memastikan bahwa semua perubahan yang mereka buat akan digulirkan kembali pada akhir batch. Biasanya, perubahan mereka dibatalkan, tetapi kadang-kadang ada pernyataan 'komit' yang eksplisit di dalam teks, dan tentu saja rollback saya tidak akan berfungsi. Komit eksplisit ini sangat mungkin dari pengguna yang mencoba memutus skema pada SQL Fiddle, sehingga orang lain yang mengerjakannya akan melihat kesalahan.

Hasil yang Diinginkan Utama : Saya ingin menonaktifkan komit eksplisit di tingkat JDBC, jika memungkinkan. Ini karena saya harus mendukung beberapa vendor backend database, dan tentu saja masing-masing memiliki kebiasaan mereka di tingkat rendah.

Opsi mundur : Jika tidak memungkinkan untuk mengkonfigurasi JDBC untuk menonaktifkan commit eksplisit, maka saya akan terbuka untuk solusi untuk mendeteksi commit eksplisit saat memproses batch untuk masing-masing backend berikut: SQL Server, Oracle, MySQL, dan PostgreSQL.

Untuk SQL Server, saya memikirkan solusi ini: parsing melalui rencana permintaan XML untuk pernyataan sebelum saya menjalankannya, dan periksa keberadaan entri yang cocok dengan XPath ini:

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

Saya pikir ini akan bekerja dengan baik untuk SQL Server. Namun, pendekatan ini tidak berfungsi untuk tipe DB lainnya. Output rencana eksekusi XML Oracle untuk komitmen eksplisit tidak merujuk pada fakta bahwa Anda menjalankan pernyataan commit (melainkan hanya mengulangi output rencana eksekusi dari kueri yang dikomitnya). PostgreSQL dan MySQL sama sekali tidak memberikan output rencana eksekusi (XML atau lainnya) untuk komitmen eksplisit.

Itu membuat saya memeriksa pernyataan aktual untuk kata "komit". Ini akan berhasil, kecuali mungkin ada semua jenis variasi yang mungkin:

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

Di atas adalah contoh untuk SQL Server (yang bisa saya selesaikan), tapi saya kira hal serupa akan mungkin untuk Oracle, MySQL, dan PostgreSQL. Apakah saya salah dengan asumsi itu? Mungkin mereka tidak akan mengizinkan pernyataan komitmen "dinamis"? Jangan ragu untuk menggunakan SQL Fiddle (lebih disukai bukan contoh skema atau satu orang lain yang mungkin akan bekerja) untuk melihat apakah Anda dapat membuat sesuatu yang serupa terjadi di Oracle, MySQL, dan PostgreSQL. Jika tidak, mungkin deteksi string sederhana mungkin berhasil untuk mereka.

Namun kemungkinan lain

Pilihan lain terpikir oleh saya - jika Anda tahu cara mengatur salah satu dari database ini dalam mode readonly, seperti dalam mode itu tidak ada yang bisa dikomit, itu bisa bekerja juga. Saya masih perlu mengizinkan transaksi untuk dimulai dan kode dijalankan di dalamnya, asalkan tidak ada yang bisa dilakukan saat dalam mode itu. Apakah itu mungkin?

Memperbarui

Apa yang saya pelajari baru-baru ini - ini sebenarnya bukan masalah dengan PostgreSQL. Tampaknya komit yang dikeluarkan dalam blok transaksi tidak akan berlaku jika blok yang sama pada akhirnya akan dibatalkan (dalam Postgres). Jadi Hore untuk Postgres!

Berkat tautan Phil ke pos SO, saya pikir saya dapat menggunakan retas AWAL DITANGGUHKAN untuk Oracle untuk mencapai apa yang saya kejar (kesalahan akan dilemparkan jika komit dikeluarkan, tetapi saya bisa mengatasinya). Ini harus mengatasi Oracle. (Saya berpikir sejenak bahwa transaksi bersarang mungkin bekerja di sini, tetapi sepertinya Oracle tidak mendukung transaksi bersarang? Lagi pula saya tidak dapat menemukan apa pun yang berfungsi seperti ini).

Belum benar-benar memiliki solusi untuk MySQL. Sudah mencoba menggunakan transaksi bersarang, tetapi itu tampaknya tidak berhasil. Saya serius memikirkan pendekatan yang lebih drastis untuk MySQL, seperti tidak mengizinkan apa pun kecuali PILIH di sisi kanan atau menjatuhkan / menciptakan kembali DB setelah setiap permintaan. Kedengarannya tidak bagus.

Resolusi

Jadi, saya sekarang telah mengimplementasikan solusi yang dijelaskan untuk SQL Server dan Oracle, dan seperti yang saya sebutkan ini sebenarnya bukan masalah untuk PostgreSQL. Untuk MySQL, saya telah mengambil langkah yang agak disayangkan yaitu membatasi panel permintaan hanya untuk memilih pernyataan. DDL dan DML untuk MySQL harus dimasukkan pada panel skema (sisi kiri). Saya harap ini tidak memecahkan terlalu banyak biola lama, tapi saya pikir itu hanya apa yang harus dilakukan untuk memastikan konsistensi data. Terima kasih!

Jake Feasel
sumber
Layak disebut - Saya juga melakukan banyak penelitian mencari pemicu "pra-komit". Tampaknya itu tidak ada, jadi sayangnya itu bukan opsi juga.
Jake Feasel
2
Untuk Oracle, ini sepertinya cara licik yang bagus untuk menangkap COMMIT: stackoverflow.com/a/6463800/790702 Apa yang tidak ia sebutkan adalah bahwa Anda harus dapat menangkap pelanggaran kendala dalam kode Anda juga, untuk menghentikan situasi ke-2. terjadi.
Philᵀᴹ
@Phil Satu-satunya masalah di sana adalah bahwa saya tidak memiliki (dan tidak benar-benar ingin) mengendalikan definisi masing-masing tabel (yang didefinisikan pada panel kiri). Sehingga klausa AWAL DITANGGUHKAN AWAL tidak akan ada (kecuali ada beberapa cara untuk melakukan itu secara otomatis untuk semua tabel - katakanlah melalui pemicu sistem yang merespons untuk membuat pernyataan tabel? Ugh)
Jake Feasel
1
@NickChammas Saya perlu menonaktifkan commit agar saya dapat menjaga skema (seperti yang didefinisikan oleh panel sisi kiri) dalam keadaan tetap. Mungkin ada sejumlah orang yang menulis kueri terhadap skema yang sama mencoba memecahkan masalah yang sama. Untuk mencegah mereka saling mengganggu, saya harus memastikan untuk menjaga struktur dan data agar tidak berubah. Ini dilakukan melalui transaksi yang digulirkan, tetapi itu tidak terjadi jika kode sisi kanan dikomit.
Jake Feasel
2
@RickJames DDL membuat commit implisit di MySQL dan Oracle, tetapi tidak di PostgreSQL atau SQL Server. Mekanisme yang saya terapkan setelah posting ini menangani masalah itu. Sejauh memasukkan SQL sewenang-wenang - itulah intinya!
Jake Feasel

Jawaban:

3

Untuk Oracle, ini sepertinya cara licik yang bagus untuk menangkap KOMIT:

/programming//a/6463800/790702

Yang tidak ia sebutkan adalah bahwa Anda harus dapat menangkap pelanggaran kendala dalam kode Anda juga, untuk menghentikan situasi kedua yang terjadi.

Philᵀᴹ
sumber
Bagus, terima kasih lagi, Phil. Saya sudah bisa memanfaatkan teknik ini untuk Oracle. Itu membuat saya berharap database lain mendukung kendala yang ditangguhkan.
Jake Feasel
Jangan khawatir. Masuk ke chat dan say hi :)
Philᵀᴹ