Saya mendapatkan pengecualian SQL ORA-01000. Jadi saya punya beberapa pertanyaan terkait dengannya.
- Apakah kursor terbuka maksimum persis terkait dengan jumlah koneksi JDBC, atau apakah juga terkait dengan objek pernyataan dan resultet yang telah kita buat untuk satu koneksi? (Kami menggunakan kumpulan koneksi)
- Apakah ada cara untuk mengkonfigurasi jumlah objek pernyataan / resultet dalam database (seperti koneksi)?
- Apakah disarankan untuk menggunakan pernyataan variabel instance / objek hasil set daripada metode objek pernyataan / hasil set lokal dalam lingkungan berulir tunggal?
Apakah mengeksekusi pernyataan yang disiapkan dalam satu lingkaran menyebabkan masalah ini? (Tentu saja, saya bisa menggunakan sqlBatch) Catatan: pStmt ditutup setelah loop selesai.
{ //method try starts String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)"; pStmt = obj.getConnection().prepareStatement(sql); pStmt.setLong(1, subscriberID); for (String language : additionalLangs) { pStmt.setInt(2, Integer.parseInt(language)); pStmt.execute(); } } //method/try ends { //finally starts pStmt.close() } //finally ends
Apa yang akan terjadi jika conn.createStatement () dan conn.prepareStatement (sql) dipanggil beberapa kali pada objek koneksi tunggal?
Sunting1: 6. Apakah penggunaan objek pernyataan referensi Lemah / Soft membantu mencegah kebocoran?
Sunting2: 1. Apakah ada cara, saya dapat menemukan semua "statement.close ()" yang hilang dalam proyek saya? Saya mengerti ini bukan kebocoran memori. Tetapi saya perlu menemukan referensi pernyataan (di mana close () tidak dilakukan) memenuhi syarat untuk pengumpulan sampah? Ada alat yang tersedia? Atau apakah saya harus menganalisisnya secara manual?
Tolong bantu saya memahaminya.
Larutan
Untuk menemukan kursor yang dibuka di Oracle DB untuk nama pengguna -VELU
Pergi ke mesin ORACLE dan mulai sqlplus sebagai sysdba.
[oracle@db01 ~]$ sqlplus / as sysdba
Lalu lari
SELECT A.VALUE,
S.USERNAME,
S.SID,
S.SERIAL#
FROM V$SESSTAT A,
V$STATNAME B,
V$SESSION S
WHERE A.STATISTIC# = B.STATISTIC#
AND S.SID = A.SID
AND B.NAME = 'opened cursors current'
AND USERNAME = 'VELU';
Jika memungkinkan silakan baca jawaban saya untuk lebih memahami solusi saya
for (String language : additionalLangs) {
SYS.V$OPEN_CURSOR
tampilan. Ini akan memberi Anda tidak hanya SID, tetapi juga teks SQL.Jawaban:
ORA-01000, kesalahan maksimum-buka-kursor, adalah kesalahan yang sangat umum dalam pengembangan database Oracle. Dalam konteks Java, ini terjadi saat aplikasi mencoba membuka lebih banyak ResultSets daripada kursor yang dikonfigurasi pada instance database.
Penyebab umumnya adalah:
Kesalahan konfigurasi
Larutan:
Kebocoran kursor
Latar Belakang
Bagian ini menjelaskan beberapa teori di balik kursor dan bagaimana JDBC harus digunakan. Jika Anda tidak perlu mengetahui latar belakangnya, Anda dapat melewati ini dan langsung ke 'Eliminating Leaks'.
Apa itu kursor?
Kursor adalah sumber daya di database yang menyimpan status kueri, khususnya posisi pembaca di ResultSet. Setiap pernyataan SELECT memiliki kursor, dan prosedur tersimpan PL / SQL dapat membuka dan menggunakan kursor sebanyak yang mereka butuhkan. Anda dapat mencari tahu lebih lanjut tentang cursors on Orafaq .
Instance database biasanya melayani beberapa skema berbeda , banyak pengguna berbeda masing-masing dengan beberapa sesi . Untuk melakukan ini, ia memiliki sejumlah kursor tetap yang tersedia untuk semua skema, pengguna dan sesi. Ketika semua kursor terbuka (sedang digunakan) dan permintaan datang yang membutuhkan kursor baru, permintaan gagal dengan kesalahan ORA-010000.
Menemukan dan mengatur jumlah kursor
Nomor tersebut biasanya dikonfigurasi oleh DBA saat penginstalan. Jumlah kursor yang saat ini digunakan, jumlah maksimum, dan konfigurasi dapat diakses di fungsi Administrator di Oracle SQL Developer . Dari SQL dapat diatur dengan:
Menghubungkan JDBC di JVM dengan kursor di DB
Objek JDBC di bawah ini terkait erat dengan konsep database berikut:
JDBC adalah thread safe: Tidak masalah untuk meneruskan berbagai objek JDBC di antara thread.
Misalnya, Anda dapat membuat koneksi dalam satu utas; utas lain dapat menggunakan koneksi ini untuk membuat PreparedStatement dan utas ketiga dapat memproses kumpulan hasil. Batasan utama tunggal adalah bahwa Anda tidak dapat membuka lebih dari satu ResultSet di satu PreparedStatement kapan saja. Lihat Apakah Oracle DB mendukung beberapa operasi (paralel) per koneksi?
Perhatikan bahwa komit database terjadi pada koneksi, dan semua DML (INSERT, UPDATE dan DELETE) pada koneksi itu akan berkomitmen bersama. Oleh karena itu, jika Anda ingin mendukung beberapa transaksi pada saat yang sama, Anda harus memiliki setidaknya satu Koneksi untuk setiap Transaksi bersamaan.
Menutup objek JDBC
Contoh khas dari mengeksekusi ResultSet adalah:
Perhatikan bagaimana klausa akhirnya mengabaikan pengecualian apa pun yang dimunculkan oleh close ():
Di Java 7, Oracle telah memperkenalkan antarmuka AutoCloseable yang menggantikan sebagian besar boilerplate Java 6 dengan beberapa gula sintaksis yang bagus.
Memegang objek JDBC
Objek JDBC dapat disimpan dengan aman di variabel lokal, instance objek, dan anggota kelas. Biasanya praktik yang lebih baik adalah:
Namun, ada satu pengecualian: Jika Anda menggunakan EJB, atau container Servlet / JSP, Anda harus mengikuti model threading yang ketat:
Menghilangkan kebocoran
Ada sejumlah proses dan alat yang tersedia untuk membantu mendeteksi dan menghilangkan kebocoran JDBC:
Selama pengembangan - menangkap bug lebih awal sejauh ini merupakan pendekatan terbaik:
Praktik pengembangan: Praktik pengembangan yang baik akan mengurangi jumlah bug di perangkat lunak Anda sebelum meninggalkan meja pengembang. Praktik khusus meliputi:
Analisis Kode Statis: Gunakan alat seperti Findbugs yang sangat baik untuk melakukan analisis kode statis. Ini mengambil banyak tempat di mana close () belum ditangani dengan benar. Findbugs memiliki plugin untuk Eclipse, tetapi juga berjalan mandiri untuk satu kali, memiliki integrasi ke Jenkins CI dan alat build lainnya
Saat runtime:
Holdability dan commit
Logging saat runtime.
Anda dapat menambahkan driver JDBC debugging ke proyek Anda (untuk debugging - tidak benar-benar menerapkannya). Salah satu contoh (saya belum pernah menggunakannya) adalah log4jdbc . Anda kemudian perlu melakukan beberapa analisis sederhana pada file ini untuk melihat eksekusi mana yang tidak memiliki penutupan yang sesuai. Menghitung pembukaan dan penutupan harus menyoroti jika ada masalah potensial
Pikiran lain
Dapatkah Anda menggunakan WeakReferences untuk menangani penutupan koneksi?
Referensi lemah dan lunak adalah cara yang memungkinkan Anda untuk mereferensikan objek dengan cara yang memungkinkan JVM mengumpulkan sampah untuk mengumpulkan referensi kapan saja dianggap sesuai (dengan asumsi tidak ada rantai referensi yang kuat ke objek tersebut).
Jika Anda meneruskan ReferenceQueue di konstruktor ke ReferenceQueue lunak atau lemah, objek tersebut ditempatkan di ReferenceQueue saat objek tersebut di-GC ketika terjadi (jika terjadi sama sekali). Dengan pendekatan ini, Anda dapat berinteraksi dengan penyelesaian objek dan Anda dapat menutup atau menyelesaikan objek pada saat itu.
Referensi phantom sedikit lebih aneh; tujuan mereka hanya untuk mengontrol penyelesaian, tetapi Anda tidak akan pernah bisa mendapatkan referensi ke objek asli, jadi akan sulit untuk memanggil metode close () di atasnya.
Namun, jarang sekali merupakan ide yang baik untuk mencoba mengontrol kapan GC dijalankan (Weak, Soft and PhantomReferences memberi tahu Anda setelah fakta bahwa objek diantrekan untuk GC). Faktanya, jika jumlah memori di JVM besar (mis. -Xmx2000m) Anda mungkin tidak akan pernah melakukan GC pada objek, dan Anda masih akan mengalami ORA-01000. Jika memori JVM relatif kecil untuk persyaratan program Anda, Anda mungkin menemukan bahwa objek ResultSet dan PreparedStatement digabungkan segera setelah pembuatan (sebelum Anda dapat membacanya), yang kemungkinan besar akan menggagalkan program Anda.
TL; DR: Mekanisme referensi yang lemah bukanlah cara yang baik untuk mengelola dan menutup objek Statement dan ResultSet.
sumber
Saya menambahkan lebih sedikit pemahaman.
Loggin sebagai sysdba.
Di Putty (login Oracle):
Di SqlPlus:
Nama pengguna:
sys as sysdba
Setel nilai session_cached_cursors ke 0 sehingga tidak akan menutup kursor.
Pilih set valuse OPEN_CURSORS yang ada per koneksi di DB
Di bawah ini adalah kueri untuk menemukan daftar SID / koneksi dengan nilai kursor terbuka.
Gunakan kueri di bawah ini untuk mengidentifikasi sql di kursor terbuka
Sekarang debug Kode dan Nikmati !!! :)
sumber
Perbaiki Kode Anda seperti ini:
Apakah Anda yakin, bahwa Anda benar-benar menutup pStatements, koneksi, dan hasil Anda?
Untuk menganalisis objek terbuka Anda bisa menerapkan pola delegator, yang membungkus kode di sekitar objek statemant, koneksi dan hasil Anda. Jadi Anda akan melihat, apakah suatu objek akan berhasil ditutup.
Contoh untuk: pStmt = obj. getConnection () .prepareStatement (sql);
sumber
Jika aplikasi Anda adalah aplikasi Java EE yang berjalan di Oracle WebLogic sebagai server aplikasi, kemungkinan penyebab masalah ini adalah Statement Cache Size di WebLogic.
Jika pengaturan Pernyataan Ukuran Cache untuk sumber data tertentu hampir sama dengan, atau lebih besar dari, pengaturan jumlah kursor terbuka maksimum database Oracle, maka semua kursor terbuka dapat dikonsumsi oleh pernyataan SQL cache yang dipegang terbuka oleh WebLogic, menghasilkan dalam kesalahan ORA-01000.
Untuk mengatasi hal ini, kurangi pengaturan Pernyataan Cache Size untuk setiap sumber data WebLogic yang mengarah ke database Oracle menjadi jauh lebih kecil daripada pengaturan jumlah kursor maksimum pada database.
Di Konsol Admin WebLogic 10, pengaturan Ukuran Cache Pernyataan untuk setiap sumber data dapat ditemukan di Services (navigasi kiri)> Sumber Data> (sumber data individual)> tab Kumpulan Koneksi.
sumber
Saya juga pernah menghadapi masalah ini. Pengecualian di bawah ini biasa datang
Saya menggunakan Spring Framework dengan Spring JDBC untuk lapisan dao.
Aplikasi saya biasanya membocorkan kursor entah bagaimana dan setelah beberapa menit atau lebih, itu memberi saya pengecualian ini.
Setelah melakukan banyak debugging dan analisis menyeluruh, saya menemukan bahwa ada masalah dengan Pengindeksan, Kunci Utama, dan Batasan Unik di salah satu Tabel yang digunakan dalam Kueri. saya jalankan.
Aplikasi saya mencoba memperbarui Kolom yang salah Indexed . Jadi, setiap kali aplikasi saya menekan permintaan pembaruan pada kolom yang diindeks, database mencoba melakukan pengindeksan ulang berdasarkan nilai yang diperbarui. Itu membocorkan kursornya .
Saya dapat memecahkan masalah dengan melakukan Pengindeksan yang Benar pada kolom yang digunakan untuk mencari di kueri dan menerapkan batasan yang sesuai di mana pun diperlukan.
sumber
Saya menghadapi masalah yang sama (ORA-01000) hari ini. Saya memiliki perulangan for dalam percobaan {}, untuk mengeksekusi pernyataan SELECT dalam Oracle DB berkali-kali, (setiap kali mengubah parameter), dan pada akhirnya {} saya memiliki kode untuk menutup Resultset, PreparedStatement dan Koneksi seperti biasa . Tetapi segera setelah saya mencapai jumlah loop tertentu (1000) saya mendapat kesalahan Oracle tentang terlalu banyak kursor yang terbuka.
Berdasarkan postingan Andrew Alcock di atas, saya melakukan perubahan sehingga di dalamnya dalam loop, saya menutup setiap kumpulan hasil dan setiap pernyataan setelah mendapatkan data dan sebelum mengulang lagi, dan itu menyelesaikan masalah.
Selain itu, masalah yang sama persis terjadi di loop lain dari Pernyataan Sisipan, di Oracle DB (ORA-01000) lain, kali ini setelah 300 pernyataan. Sekali lagi itu diselesaikan dengan cara yang sama, jadi PreparedStatement atau ResultSet atau keduanya, dihitung sebagai kursor terbuka sampai ditutup.
sumber
Apakah Anda menyetel autocommit = true? Jika tidak coba ini:
sumber
query untuk menemukan sql yang dibuka.
sumber
Masalah ini terutama terjadi ketika Anda menggunakan penggabungan koneksi karena ketika Anda menutup koneksi koneksi itu kembali ke kumpulan koneksi dan semua kursor yang terkait dengan koneksi itu tidak pernah ditutup karena koneksi ke database masih terbuka. Jadi salah satu alternatif adalah untuk mengurangi waktu koneksi idle koneksi di pool, jadi mungkin setiap kali koneksi diam dalam koneksi katakanlah 10 detik, koneksi ke database akan ditutup dan koneksi baru dibuat untuk dimasukkan ke dalam pool.
sumber
Menggunakan pemrosesan batch akan menghasilkan lebih sedikit overhead. Lihat tautan berikut untuk contoh: http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm
sumber
Dalam kasus kami, kami menggunakan Hibernate dan kami memiliki banyak variabel yang merujuk ke entitas yang dipetakan Hibernate yang sama. Kami membuat dan menyimpan referensi ini dalam satu lingkaran. Setiap referensi membuka kursor dan membuatnya tetap terbuka.
Kami menemukan ini dengan menggunakan kueri untuk memeriksa jumlah kursor yang terbuka saat menjalankan kode kami, melangkah melalui debugger dan secara selektif memberi komentar.
Mengenai mengapa setiap referensi baru membuka kursor lain - entitas yang dimaksud memiliki kumpulan entitas lain yang dipetakan padanya dan saya pikir ini ada hubungannya dengan itu (mungkin tidak hanya ini saja tetapi dalam kombinasi dengan bagaimana kita telah mengonfigurasi mode pengambilan dan pengaturan cache). Hibernate sendiri memiliki bug di sekitar yang gagal ditutup kursor terbuka, meskipun sepertinya ini telah diperbaiki di versi yang lebih baru.
Karena kita tidak benar-benar perlu memiliki begitu banyak referensi duplikat ke entitas yang sama, solusinya adalah berhenti membuat dan menyimpan semua referensi yang berlebihan tersebut. Setelah kami melakukan itu masalah saat pergi.
sumber
Saya mengalami masalah ini dengan sumber data saya di WildFly dan Tomcat, menghubungkan ke Oracle 10g.
Saya menemukan bahwa dalam kondisi tertentu pernyataan itu tidak ditutup bahkan ketika pernyataan.close () dipanggil. Masalahnya adalah dengan Driver Oracle yang kami gunakan: ojdbc7.jar. Driver ini ditujukan untuk Oracle 12c dan 11g, dan tampaknya memiliki beberapa masalah saat digunakan dengan Oracle 10g, jadi saya menurunkan versi ke ojdbc5.jar dan sekarang semuanya berjalan dengan baik.
sumber
Saya menghadapi masalah yang sama karena saya meminta db untuk lebih dari 1000 iterasi. Saya telah menggunakan try dan akhirnya dalam kode saya. Namun masih mendapatkan error.
Untuk mengatasi ini, saya baru saja masuk ke oracle db dan menjalankan kueri di bawah ini:
ALTER SYSTEM SET open_cursors = 8000 LINGKUP = KEDUA;
Dan ini segera menyelesaikan masalah saya.
sumber