Mengapa saya memerlukan Transaksi dalam mode Hibernasi untuk operasi hanya baca?

107

Mengapa saya memerlukan Transaksi dalam mode Hibernasi untuk operasi hanya baca?

Apakah transaksi berikut mengunci DB?

Contoh kode untuk diambil dari DB:

Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here

tx.commit() // why tx.commit? I don't want to write anything

Bisakah saya menggunakan session.close() sebagai pengganti tx.commit()?

pengguna93796
sumber
9
Transaksi dibutuhkan oleh DB itu sendiri. Anda dapat membaca tentang mode
komitmen otomatis di
@BheshGurung saya rasa kami memerlukan transkasi hanya untuk operasi tulis
pengguna93796
4
Apakah Anda membaca bagian "Membongkar mitos komit otomatis" di tautan?
Bhesh Gurung

Jawaban:

131

Anda mungkin sebenarnya memiliki alasan untuk menandai transaksi sebagai hanya baca.

  1. Transaksi pembacaan mungkin memang terlihat aneh dan seringkali orang tidak menandai metode transaksi dalam kasus ini. Tetapi JDBC akan tetap membuat transaksi, hanya saja JDBC akan berfungsi autocommit=truejika opsi berbeda tidak ditetapkan secara eksplisit.
  2. Tetapi tidak ada jaminan bahwa metode Anda tidak menulis ke dalam database. Jika Anda menandai metode sebagai @Transactional(readonly=true), Spring akan mengatur transaksi JDBC ke mode hanya-baca, sehingga Anda akan menentukan apakah itu benar - benar mungkin untuk menulis ke dalam DB dalam lingkup transaksi ini. Jika arsitektur Anda rumit dan beberapa anggota tim mungkin memilih untuk meletakkan kueri modifikasi di tempat yang tidak diharapkan, tanda ini akan mengarahkan Anda ke tempat yang bermasalah.
  3. Juga transaksi hanya-baca dapat dioptimalkan oleh DB, tetapi ini tentu saja khusus DB. Misalnya MySQL menambahkan dukungan untuk ini hanya di InnoDB mulai dari versi 5.6.4.
  4. Jika Anda tidak menggunakan JDBC secara langsung, melainkan ORM, itu mungkin bermasalah. Misalnya komunitas Hibernate mengatakan bahwa bekerja di luar transaksi dapat menyebabkan perilaku yang tidak dapat diprediksi. Ini karena Hibernate akan membuka transaksi, tetapi tidak akan menutupnya sendiri, sehingga koneksi akan dikembalikan ke Connection Pool dengan transaksi tidak dilakukan. Lalu apa yang terjadi? JDBC tetap diam, jadi ini adalah implementasi spesifik (MySQL rolls transaksi kembali, Oracle afair melakukannya). Ini juga dapat dikonfigurasi pada level Connection Pool (mis. C3P0 memberi Anda opsi seperti itu, rollback secara default).
  5. Hal lain ketika datang ke Hibernate, Spring mengatur FlushMode ke MANUAL jika terjadi transaksi hanya-baca, yang mengarah ke pengoptimalan lain seperti tidak perlu pemeriksaan kotor.
  6. Anda mungkin ingin mengganti atau menyetel secara eksplisit tingkat isolasi transaksi. Ini berdampak pada transaksi baca juga karena Anda ingin atau tidak ingin membaca perubahan yang tidak terikat, terkena pembacaan bayangan, dll.

Singkatnya - Anda bisa pergi dua arah, tetapi Anda perlu memahami konsekuensinya.

Stanislav Bashkyrtsev
sumber
Terima kasih telah membalas. Saya menggunakan hibernate (hibernate asli, bukan jpa). Tetapi hibernate memaksa saya untuk memulai transkasi sebelum melakukan operasi db. Jika saya tidak memulainya, akan muncul kesalahan yang mengatakan tidak ada tracscationn yang aktif. Dapatkah saya menandai transkasi sebagai hanya baca , jika ya bagaimana?
pengguna93796
Bendera hanya-baca sebenarnya disetel untuk koneksi, bukan untuk transaksi itu sendiri, dan Anda tidak dapat mengaksesnya melalui Hibernate begitu saja. Anda perlu menggunakan dukungan Spring Transaction dan menggunakan anotasi atau konfigurasi transaksional berbasis XML. Dengan melakukan itu Spring mengambil kepemilikan koneksi dan manajemen transaksi, bukan Hibernate.
Stanislav Bashkyrtsev
1
Dijelaskan dengan sangat baik! Artikel lain dari Mark Richards menjelaskan dengan cukup baik perangkap bendera hanya-baca dalam anotasi Transaksional - ibm.com/developerworks/java/library/j-ts1/index.html .
Mahesh
48

Semua pernyataan database dijalankan dalam konteks transaksi fisik, bahkan ketika kami tidak secara eksplisit menyatakan batasan transaksi (BEGIN / COMMIT / ROLLBACK).

Jika Anda tidak mendeklarasikan batasan transaksi secara eksplisit, maka setiap pernyataan harus dieksekusi dalam transaksi terpisah (autocommit mode) terpisah. Ini bahkan dapat menyebabkan membuka dan menutup satu koneksi per pernyataan kecuali lingkungan Anda dapat menangani pengikatan koneksi-per-utas.

Menyatakan layanan sebagai @Transactional akan memberi Anda satu koneksi untuk seluruh durasi transaksi, dan semua pernyataan akan menggunakan koneksi isolasi tunggal tersebut. Ini jauh lebih baik daripada tidak menggunakan transaksi eksplisit sejak awal.

Pada aplikasi besar, Anda mungkin memiliki banyak permintaan bersamaan, dan mengurangi tingkat permintaan akuisisi koneksi database pasti akan meningkatkan kinerja aplikasi Anda secara keseluruhan.

JPA tidak memberlakukan transaksi pada operasi baca. Hanya operasi tulis yang akhirnya memunculkan pengecualian yang diperlukan transaksi jika Anda lupa memulai konteks transaksional. Namun demikian, selalu lebih baik untuk menyatakan batas transaksi bahkan untuk transaksi hanya-baca (di Spring @Transactionalmemungkinkan Anda menandai transaksi hanya-baca, yang memiliki manfaat kinerja yang hebat).

Vlad Mihalcea
sumber
1
"... maka setiap pernyataan harus dieksekusi dalam transaksi terpisah". Penampung tidak melakukan Pemrosesan Batch secara otomatis?
Arash
Pemrosesan batch adalah untuk modifikasi, bukan untuk membaca data. Meski begitu, batching JDBC tidak diaktifkan secara default saat menggunakan JPA dan Hibernate.
Vlad Mihalcea
1
Terima kasih Vlad. Saya membaca beberapa artikel Anda. Mereka sangat berguna.
Arash
Stackoverflow.com/q/34797480/179850 ini tampaknya sedikit bertentangan dengan penegasan Anda bahwa transaksi hanya baca memiliki manfaat kinerja yang hebat. Setidaknya, tampaknya tidak demikian dalam konteks hibernasi.
nimai
Tidak, tidak. Itu tentang menyetel hanya-baca, sedangkan milik saya adalah tentang menghindari komit otomatis.
Vlad Mihalcea
18

Transaksi memang mengunci database - mesin database yang baik menangani kunci bersamaan dengan cara yang masuk akal - dan berguna dengan penggunaan hanya-baca untuk memastikan bahwa tidak ada yang lain. transaksi menambahkan data yang membuat tampilan Anda tidak konsisten. Anda selalu menginginkan transaksi (meskipun kadang-kadang masuk akal untuk menyesuaikan tingkat isolasi, sebaiknya jangan lakukan itu sejak awal); jika Anda tidak pernah menulis ke DB selama transaksi Anda, baik melakukan maupun mengembalikan transaksi akan sama (dan sangat murah).

Sekarang, jika Anda beruntung dan kueri Anda terhadap DB sedemikian rupa sehingga ORM selalu memetakannya ke kueri SQL tunggal, Anda dapat lolos tanpa transaksi eksplisit , mengandalkan perilaku autocommit bawaan DB, tetapi ORM adalah sistem yang relatif kompleks jadi sama sekali tidak aman untuk mengandalkan perilaku seperti itu kecuali jika Anda bekerja lebih keras untuk memeriksa apa yang sebenarnya dilakukan oleh implementasi. Menulis batas transaksi eksplisit jauh lebih mudah untuk dilakukan dengan benar (terutama jika Anda dapat melakukannya dengan AOP atau teknik serupa yang digerakkan ORM; dari Java 7 dan seterusnya coba-dengan-sumber daya dapat digunakan juga, saya kira).

Donal Fellows
sumber
14

Tidak masalah apakah Anda hanya membaca atau tidak - database harus tetap melacak kumpulan hasil Anda, karena klien database lain mungkin ingin menulis data yang akan mengubah kumpulan hasil Anda.

Saya telah melihat program yang salah untuk membunuh sistem database yang besar, karena mereka hanya membaca data, tetapi tidak pernah melakukan, memaksa log transaksi untuk berkembang, karena DB tidak dapat merilis data transaksi sebelum COMMIT atau ROLLBACK, bahkan jika klien tidak melakukan apa pun selama berjam-jam.

Ingo
sumber