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!