Saya memiliki kueri baca yang saya jalankan dalam suatu transaksi sehingga saya dapat menentukan tingkat isolasi. Setelah kueri selesai, apa yang harus saya lakukan?
- Lakukan transaksi
- Rollback transaksi
- Tidak melakukan apa-apa (yang akan menyebabkan transaksi dibatalkan pada akhir blok penggunaan)
Apa implikasi dari melakukan masing-masing?
using (IDbConnection connection = ConnectionFactory.CreateConnection())
{
using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
{
using (IDbCommand command = connection.CreateCommand())
{
command.Transaction = transaction;
command.CommandText = "SELECT * FROM SomeTable";
using (IDataReader reader = command.ExecuteReader())
{
// Read the results
}
}
// To commit, or not to commit?
}
}
EDIT: Pertanyaannya bukan apakah transaksi harus digunakan atau jika ada cara lain untuk mengatur level transaksi. Pertanyaannya adalah jika ada bedanya bahwa transaksi yang tidak mengubah apa pun telah dilakukan atau dibatalkan. Apakah ada perbedaan kinerja? Apakah itu mempengaruhi koneksi lain? Ada perbedaan lain?
sql
database
transactions
Stefan Moser
sumber
sumber
Jawaban:
Anda berkomitmen. Titik. Tidak ada alternatif lain yang masuk akal. Jika Anda memulai transaksi, Anda harus menutupnya. Committing melepaskan semua kunci yang mungkin Anda miliki, dan sama-sama masuk akal dengan tingkat isolasi ReadUncommitted atau Serializable. Mengandalkan rollback implisit - meski mungkin secara teknis setara - hanyalah bentuk yang buruk.
Jika itu belum meyakinkan Anda, bayangkan saja orang berikutnya yang menyisipkan pernyataan pembaruan di tengah kode Anda, dan harus melacak rollback implisit yang terjadi dan menghapus datanya.
sumber
Jika Anda belum mengubah apa pun, Anda dapat menggunakan COMMIT atau ROLLBACK. Salah satu dari mereka akan melepaskan kunci baca yang telah Anda peroleh dan karena Anda belum membuat perubahan apa pun, kunci tersebut akan setara.
sumber
Jika Anda memulai transaksi, praktik terbaiknya adalah selalu melakukannya. Jika pengecualian dilemparkan ke dalam blok penggunaan (transaksi) Anda, transaksi akan secara otomatis dibatalkan.
sumber
IMHO masuk akal untuk membungkus kueri hanya baca dalam transaksi karena (terutama di Java) Anda dapat memberi tahu transaksi menjadi "hanya-baca" yang pada gilirannya driver JDBC dapat mempertimbangkan untuk mengoptimalkan kueri (tetapi tidak harus, jadi tidak ada akan mencegah Anda dari mengeluarkan a
INSERT
). Misalnya driver Oracle akan sepenuhnya menghindari penguncian tabel pada kueri dalam transaksi yang ditandai hanya-baca, yang memperoleh banyak kinerja pada aplikasi yang sangat berorientasi baca.sumber
Pertimbangkan transaksi bersarang .
Kebanyakan RDBMS tidak mendukung transaksi bersarang, atau mencoba meniru mereka dengan cara yang sangat terbatas.
Misalnya, di MS SQL Server, rollback dalam transaksi dalam (yang bukan transaksi nyata, MS SQL Server hanya menghitung level transaksi!) Akan mengembalikan semua yang telah terjadi di transaksi terluar (yang merupakan transaksi nyata).
Beberapa pembungkus database mungkin mempertimbangkan rollback dalam transaksi dalam sebagai tanda bahwa kesalahan telah terjadi dan mengembalikan semua yang ada di transaksi terluar, terlepas apakah transaksi terluar dilakukan atau dibatalkan.
Jadi COMMIT adalah cara yang aman, ketika Anda tidak dapat mengesampingkan bahwa komponen Anda digunakan oleh beberapa modul perangkat lunak.
Harap dicatat bahwa ini adalah jawaban umum untuk pertanyaan tersebut. Contoh kode secara cerdik mengatasi masalah dengan transaksi luar dengan membuka koneksi database baru.
Mengenai kinerja: tergantung pada tingkat isolasi, PILIHAN mungkin memerlukan berbagai tingkat KUNCI dan data sementara (snapshot). Ini dibersihkan saat transaksi ditutup. Tidak masalah apakah ini dilakukan melalui COMMIT atau ROLLBACK. Mungkin ada perbedaan yang tidak signifikan dalam waktu CPU yang dihabiskan - COMMIT mungkin lebih cepat untuk diurai daripada ROLLBACK (dua karakter lebih sedikit) dan perbedaan kecil lainnya. Jelas, ini hanya berlaku untuk operasi read-only!
Sama sekali tidak ditanyakan: programmer lain yang mungkin bisa membaca kode mungkin berasumsi bahwa ROLLBACK menyiratkan kondisi kesalahan.
sumber
Sekadar catatan, tetapi Anda juga dapat menulis kode itu seperti ini:
Dan jika Anda menyusun ulang sedikit, Anda mungkin dapat memindahkan blok penggunaan untuk IDataReader ke atas juga.
sumber
Jika Anda memasukkan SQL ke dalam prosedur tersimpan dan menambahkan ini di atas kueri:
maka Anda tidak perlu melewati rintangan apa pun di kode C #. Menyetel tingkat isolasi transaksi dalam prosedur tersimpan tidak menyebabkan setelan diterapkan ke semua penggunaan koneksi tersebut di masa mendatang (yang merupakan sesuatu yang harus Anda khawatirkan dengan setelan lain karena koneksi tersebut digabungkan). Pada akhir prosedur tersimpan, itu hanya kembali ke koneksi apa pun yang diinisialisasi.
sumber
ROLLBACK sebagian besar digunakan jika terjadi kesalahan atau keadaan luar biasa, dan COMMIT jika penyelesaian berhasil.
Kita harus menutup transaksi dengan COMMIT (untuk sukses) dan ROLLBACK (untuk kegagalan), bahkan dalam kasus transaksi hanya-baca yang tampaknya tidak menjadi masalah. Sebenarnya itu penting, untuk konsistensi dan pembuktian masa depan.
Transaksi hanya-baca secara logis dapat "gagal" dalam banyak hal, misalnya:
Jika COMMIT dan ROLLBACK digunakan dengan benar untuk transaksi hanya-baca, itu akan terus berfungsi seperti yang diharapkan jika kode tulis DB ditambahkan di beberapa titik, misalnya untuk caching, audit atau statistik.
ROLLBACK implisit hanya boleh digunakan untuk situasi "kesalahan fatal", ketika aplikasi crash atau keluar dengan kesalahan yang tidak dapat dipulihkan, kegagalan jaringan, kegagalan daya, dll.
sumber
Mengingat bahwa BACA tidak mengubah status, saya tidak akan melakukan apa pun. Melakukan komit tidak akan melakukan apa-apa, kecuali menyia-nyiakan siklus untuk mengirim permintaan ke database. Anda belum melakukan operasi yang statusnya berubah. Begitu juga untuk rollback.
Namun Anda harus, pastikan untuk membersihkan objek Anda dan menutup koneksi Anda ke database. Tidak menutup koneksi Anda dapat menyebabkan masalah jika kode ini dipanggil berulang kali.
sumber
Jika Anda menyetel AutoCommit false, maka YA.
Dalam percobaan dengan JDBC (driver Postgresql), saya menemukan bahwa jika kueri pemilihan terputus (karena batas waktu), maka Anda tidak dapat memulai kueri pemilihan baru kecuali Anda melakukan rollback.
sumber
Dalam contoh kode Anda, di mana Anda memilikinya
// Lakukan sesuatu yang berguna
Apakah Anda menjalankan Pernyataan SQL yang mengubah data?
Jika tidak, tidak ada yang namanya Transaksi "Baca" ... Hanya perubahan dari Pernyataan Sisipkan, Perbarui, dan Hapus (pernyataan yang dapat mengubah data) berada dalam Transaksi ... Yang Anda bicarakan adalah kunci yang SQL Server memakai data yang Anda baca, karena transaksi LAIN yang mempengaruhi data itu. Tingkat kunci ini bergantung pada Tingkat Isolasi SQL Server.
Tetapi Anda tidak dapat melakukan, atau mengembalikan apa pun, jika pernyataan SQL Anda tidak mengubah apa pun.
Jika Anda mengubah data, maka Anda dapat mengubah tingkat isolasi tanpa secara eksplisit memulai transaksi ... Setiap Pernyataan SQL secara implisit ada dalam transaksi. memulai Transaksi secara eksplisit hanya diperlukan untuk memastikan bahwa 2 atau lebih pernyataan berada dalam transaksi yang sama.
Jika yang ingin Anda lakukan hanyalah menyetel tingkat isolasi transaksi, cukup setel CommandText perintah ke "Setel Transaction Isolation level Repeatable Read" (atau tingkat apa pun yang Anda inginkan), setel CommandType ke CommandType.Text, dan jalankan perintah. (Anda dapat menggunakan Command.ExecuteNonQuery ())
CATATAN: Jika Anda melakukan pernyataan baca GANDA, dan ingin semuanya "melihat" status database yang sama seperti yang pertama, maka Anda perlu mengatur isolasi Level atas Pembacaan Berulang atau Serializable ...
sumber
Apakah Anda perlu memblokir orang lain agar tidak membaca data yang sama? Mengapa menggunakan transaksi?
@Joel - Pertanyaan saya akan lebih baik diutarakan sebagai "Mengapa menggunakan transaksi pada permintaan baca?"
@ Stefan - Jika Anda akan menggunakan AdHoc SQL dan bukan proc yang disimpan, cukup tambahkan WITH (NOLOCK) setelah tabel dalam kueri. Dengan cara ini Anda tidak dikenakan biaya tambahan (meskipun minimal) dalam aplikasi dan database untuk transaksi.
EDIT @ Komentar 3: Karena Anda memiliki "sqlserver" di tag pertanyaan, saya berasumsi bahwa MSSQLServer adalah produk target. Sekarang poin itu telah diklarifikasi, saya telah mengedit tag untuk menghapus referensi produk tertentu.
Saya masih tidak yakin mengapa Anda ingin melakukan transaksi pada operasi baca di tempat pertama.
sumber