java.sql.SQLException: - ORA-01000: kursor terbuka maksimum terlampaui

115

Saya mendapatkan pengecualian SQL ORA-01000. Jadi saya punya beberapa pertanyaan terkait dengannya.

  1. 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)
  2. Apakah ada cara untuk mengkonfigurasi jumlah objek pernyataan / resultet dalam database (seperti koneksi)?
  3. Apakah disarankan untuk menggunakan pernyataan variabel instance / objek hasil set daripada metode objek pernyataan / hasil set lokal dalam lingkungan berulir tunggal?
  4. 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 
    
  5. 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

Kanagavelu Sugumar
sumber
Bisakah Anda memposting kode lengkap Anda? Akan menarik untuk melihat di mana Anda menutup kurung kurawal bukafor (String language : additionalLangs) {
Jåcob
@ Kanagavelu Sugumar: mengapa tidak menanyakan 5 pertanyaan berbeda di SO?
Jayan
1
Berikut tanggapan yang menurut saya sangat berguna: stackoverflow.com/a/4507507/501113
chaotic3quilibrium
Silakan lihat apakah jawabannya berguna: stackoverflow.com/questions/34716456/…
Manu
Untuk melacak kursor terbuka di Oracle, Anda mungkin juga ingin melihat SYS.V$OPEN_CURSORtampilan. Ini akan memberi Anda tidak hanya SID, tetapi juga teks SQL.
Bass

Jawaban:

290

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:

  1. Kesalahan konfigurasi

    • Anda memiliki lebih banyak thread dalam aplikasi Anda yang meminta database daripada kursor di DB. Satu kasus adalah saat Anda memiliki koneksi dan kumpulan thread yang lebih besar dari jumlah kursor pada database.
    • Anda memiliki banyak pengembang atau aplikasi yang terhubung ke instans DB yang sama (yang mungkin akan menyertakan banyak skema) dan bersama-sama Anda menggunakan terlalu banyak koneksi.
    • Larutan:

  2. Kebocoran kursor

    • Aplikasi tidak menutup ResultSets (di JDBC) atau kursor (dalam prosedur yang tersimpan di database)
    • Solusi : Kebocoran kursor adalah bug; meningkatkan jumlah kursor pada DB hanya akan menunda kegagalan yang tak terhindarkan. Kebocoran dapat ditemukan menggunakan analisis kode statis , JDBC atau pencatatan tingkat aplikasi, dan pemantauan basis data .

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:

ALTER SYSTEM SET OPEN_CURSORS=1337 SID='*' SCOPE=BOTH;

Menghubungkan JDBC di JVM dengan kursor di DB

Objek JDBC di bawah ini terkait erat dengan konsep database berikut:

  • JDBC Connection adalah representasi klien dari sesi database dan menyediakan transaksi database . Koneksi hanya dapat memiliki satu transaksi yang terbuka pada satu waktu (tetapi transaksi dapat bersarang)
  • ResultSet JDBC didukung oleh satu kursor pada database. Saat close () dipanggil di ResultSet, kursor dilepaskan.
  • JDBC CallableStatement menjalankan prosedur tersimpan di database, sering kali ditulis dalam PL / SQL. Prosedur tersimpan dapat membuat nol atau lebih kursor, dan dapat mengembalikan kursor sebagai JDBC ResultSet.

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:

Statement stmt = conn.createStatement();
try {
    ResultSet rs = stmt.executeQuery( "SELECT FULL_NAME FROM EMP" );
    try {
        while ( rs.next() ) {
            System.out.println( "Name: " + rs.getString("FULL_NAME") );
        }
    } finally {
        try { rs.close(); } catch (Exception ignore) { }
    }
} finally {
    try { stmt.close(); } catch (Exception ignore) { }
}

Perhatikan bagaimana klausa akhirnya mengabaikan pengecualian apa pun yang dimunculkan oleh close ():

  • Jika Anda cukup menutup ResultSet tanpa try {} catch {}, itu mungkin gagal dan mencegah Pernyataan ditutup
  • Kami ingin mengizinkan pengecualian apa pun yang dimunculkan dalam isi percobaan untuk disebarkan ke pemanggil. Jika Anda memiliki loop, misalnya, membuat dan mengeksekusi Pernyataan, ingatlah untuk menutup setiap Pernyataan dalam loop.

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:

  • Gunakan contoh objek atau anggota kelas untuk menyimpan objek JDBC yang digunakan kembali beberapa kali selama periode yang lebih lama, seperti Connections dan PreparedStatements
  • Gunakan variabel lokal untuk ResultSets karena ini diperoleh, diulangi dan kemudian ditutup biasanya dalam lingkup fungsi tunggal.

Namun, ada satu pengecualian: Jika Anda menggunakan EJB, atau container Servlet / JSP, Anda harus mengikuti model threading yang ketat:

  • Hanya Server Aplikasi yang membuat utas (yang dengannya ia menangani permintaan masuk)
  • Hanya Server Aplikasi yang membuat koneksi (yang Anda peroleh dari kumpulan koneksi)
  • Saat menyimpan nilai (status) di antara panggilan, Anda harus sangat berhati-hati. Jangan pernah menyimpan nilai dalam cache Anda sendiri atau anggota statis - ini tidak aman di seluruh kluster dan kondisi aneh lainnya, dan Server Aplikasi dapat melakukan hal-hal buruk pada data Anda. Sebagai gantinya gunakan kacang stateful atau database.
  • Secara khusus, jangan pernah menahan objek JDBC (Connections, ResultSets, PreparedStatements, dll) melalui pemanggilan jarak jauh yang berbeda - biarkan Application Server mengatur ini. Application Server tidak hanya menyediakan kumpulan koneksi, itu juga menyimpan PreparedStatements Anda.

Menghilangkan kebocoran

Ada sejumlah proses dan alat yang tersedia untuk membantu mendeteksi dan menghilangkan kebocoran JDBC:

  1. Selama pengembangan - menangkap bug lebih awal sejauh ini merupakan pendekatan terbaik:

    1. Praktik pengembangan: Praktik pengembangan yang baik akan mengurangi jumlah bug di perangkat lunak Anda sebelum meninggalkan meja pengembang. Praktik khusus meliputi:

      1. Pemrograman pasangan , untuk mendidik mereka yang tidak memiliki pengalaman yang memadai
      2. Ulasan kode karena banyak mata lebih baik dari satu
      3. Pengujian unit yang berarti Anda dapat menggunakan setiap dan semua basis kode Anda dari alat uji yang membuat mereproduksi kebocoran menjadi sepele
      4. Gunakan pustaka yang ada untuk penggabungan koneksi daripada membuat sendiri
    2. 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

  2. Saat runtime:

    1. Holdability dan commit

      1. Jika kemampuan ResultSet adalah ResultSet.CLOSE_CURSORS_OVER_COMMIT, maka ResultSet ditutup ketika metode Connection.commit () dipanggil. Ini bisa disetel menggunakan Connection.setHoldability () atau dengan menggunakan metode Connection.createStatement () yang kelebihan beban.
    2. Logging saat runtime.

      1. Letakkan pernyataan log yang baik di kode Anda. Ini harus jelas dan dapat dimengerti sehingga pelanggan, staf pendukung, dan rekan tim dapat memahami tanpa pelatihan. Mereka harus singkat dan mencakup pencetakan status / nilai internal variabel dan atribut kunci sehingga Anda dapat melacak logika pemrosesan. Pencatatan yang baik sangat penting untuk men-debug aplikasi, terutama yang telah diterapkan.
      2. 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

        1. Memantau database. Pantau aplikasi Anda yang sedang berjalan menggunakan alat seperti fungsi SQL Developer 'Monitor SQL' atau Quest's TOAD . Pemantauan dijelaskan dalam artikel ini . Selama pemantauan, Anda meminta kursor terbuka (misalnya dari tabel v $ sesstat) dan meninjau SQL-nya. Jika jumlah kursor meningkat, dan (yang paling penting) didominasi oleh satu pernyataan SQL yang identik, Anda tahu bahwa Anda memiliki kebocoran dengan SQL tersebut. Telusuri kode Anda dan tinjau.

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.

Andrew Alcock
sumber
3
Jika Anda membuat pernyataan dalam satu loop, pastikan itu ditutup dalam loop lain, Anda hanya akan menutup pernyataan terakhir.
basiljames
Terima kasih, basiljames. Baru saja mengedit jawaban untuk menambahkan poin yang Anda buat.
Andrew Alcock
@ Andrew Alcock Terima kasih banyak! Andrew. Bisakah Anda menjawab yang ke-6 juga.
Kanagavelu Sugumar
@AndrewAlcock Tolong .. tolong .. tolong .. jawab pertanyaan saya yang ke 7 juga. Sejak proyek kami, kami sangat sering menghadapi ORA-01000 saat pengujian beban. Masukan Anda lebih berharga bagi saya. Terimakasih banyak sebelumnya!!
Kanagavelu Sugumar
RE: 7 - Anda dapat mencoba pencarian jarak menggunakan alat seperti grep. Saat Anda mengenali SQL (pilih, sisipkan, perbarui, hapus), lihat kedekatan kata close () di sebelah pernyataan. Jika kedekatannya lebih jauh dari yang diharapkan, itu mungkin cara untuk menyelidiki di mana itu hilang. lightboxtechnologies.com/2012/07/27/…
Minggu
28

Saya menambahkan lebih sedikit pemahaman.

  1. Kursor hanya tentang objek pernyataan; Ini bukan resultSet atau objek koneksi.
  2. Tapi tetap kita harus menutup kumpulan hasil untuk membebaskan beberapa memori oracle. Masih jika Anda tidak menutup kumpulan hasil yang tidak akan dihitung untuk CURSORS.
  3. Objek Closing Statement juga akan secara otomatis menutup objek resultet.
  4. Kursor akan dibuat untuk semua pernyataan SELECT / INSERT / UPDATE / DELETE.
  5. Setiap instans ORACLE DB dapat diidentifikasi menggunakan oracle SID; Demikian pula ORACLE DB dapat mengidentifikasi setiap koneksi menggunakan koneksi SID. Kedua SID berbeda.
  6. Jadi sesi ORACLE tidak lain adalah koneksi jdbc (tcp); yang tidak lain adalah satu SID.
  7. Jika kita menetapkan kursor maksimum 500 maka itu hanya untuk satu sesi / koneksi / SID JDBC.
  8. Jadi kita dapat memiliki banyak koneksi JDBC dengan no cursor (pernyataan) masing-masing.
  9. Setelah JVM diakhiri, semua koneksi / kursor akan ditutup, ATAU JDBCConnection ditutup KURSOR sehubungan dengan koneksi itu akan ditutup.

Loggin sebagai sysdba.

Di Putty (login Oracle):

  [oracle@db01 ~]$ sqlplus / as sysdba

Di SqlPlus:

Nama pengguna: sys as sysdba

Setel nilai session_cached_cursors ke 0 sehingga tidak akan menutup kursor.

 alter session set session_cached_cursors=0
 select * from V$PARAMETER where name='session_cached_cursors'

Pilih set valuse OPEN_CURSORS yang ada per koneksi di DB

 SELECT max(a.value) as highest_open_cur, p.value as max_open_cur FROM v$sesstat a, v$statname b, v$parameter p WHERE a.statistic# = b.statistic# AND b.name = 'opened cursors current' AND p.name= 'open_cursors'  GROUP BY p.value;

Di bawah ini adalah kueri untuk menemukan daftar SID / koneksi dengan nilai kursor terbuka.

 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 = 'SCHEMA_NAME_IN_CAPS'

Gunakan kueri di bawah ini untuk mengidentifikasi sql di kursor terbuka

 SELECT oc.sql_text, s.sid 
 FROM v$open_cursor oc, v$session s
 WHERE OC.sid = S.sid
 AND s.sid=1604
 AND OC.USER_NAME ='SCHEMA_NAME_IN_CAPS'

Sekarang debug Kode dan Nikmati !!! :)

Kanagavelu Sugumar
sumber
1
Berikut adalah kueri lain yang tampaknya berfungsi dengan baik: stackoverflow.com/a/2560415/32453
rogerdpack
4

Perbaiki Kode Anda seperti ini:

try
{ //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
{ //finally starts
   pStmt.close()
} 

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);

    class obj{ 

    public Connection getConnection(){
    return new ConnectionDelegator(...here create your connection object and put it into ...);

    } 
}


class ConnectionDelegator implements Connection{
    Connection delegates;

    public ConnectionDelegator(Connection con){
       this.delegates = con;
    }

    public Statement prepareStatement(String sql){
        return delegates.prepareStatement(sql);
    }

    public void close(){
        try{
           delegates.close();
        }finally{
           log.debug(delegates.toString() + " was closed");
        }
    }
}
Mirko
sumber
3

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.

Jon Schneider
sumber
1
Hibernate memiliki cache Pernyataan juga. Lihat juga developer.jboss.org/wiki/…
Pino
3

Saya juga pernah menghadapi masalah ini. Pengecualian di bawah ini biasa datang

java.sql.SQLException: - ORA-01000: maximum open cursors exceeded

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.

Piyush Verma
sumber
2

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.

Kinnison84
sumber
Ini sepertinya tidak benar. Dokumen Spring yang bertanggung jawab untuk menutup ResultSets ( docs.spring.io/spring/docs/current/spring-framework-reference/… ).
Ryan
hanya untuk klarifikasi, dalam contoh tersebut saya tidak menggunakan Spring.
Kinnison84
1

Apakah Anda menyetel autocommit = true? Jika tidak coba ini:

{ //method try starts  
    String sql = "INSERT into TblName (col1, col2) VALUES(?, ?)";
    Connection conn = obj.getConnection()
    pStmt = conn.prepareStatement(sql);

    for (String language : additionalLangs) {
        pStmt.setLong(1, subscriberID);
        pStmt.setInt(2, Integer.parseInt(language));
        pStmt.execute();
        conn.commit();
    }
} //method/try ends { 
    //finally starts
    pStmt.close()
} //finally ends 
paweloque.dll
sumber
Bisakah Anda menjawab pertanyaan lain juga?
Kanagavelu Sugumar
2
Autocommit tidak menutup koneksi - hanya secara otomatis melakukan setiap pernyataan segera setelah eksekusi. Jika Anda menggunakan autocommit, Anda tidak mendapatkan nilai dari salah satu properti paling penting database - transaksi. Anda dapat mempertimbangkan untuk menggunakan DB NoSQL sebagai gantinya.
Andrew Alcock
1

query untuk menemukan sql yang dibuka.

SELECT s.machine, oc.user_name, oc.sql_text, count(1) 
FROM v$open_cursor oc, v$session s
WHERE oc.sid = s.sid
and S.USERNAME='XXXX'
GROUP BY user_name, sql_text, machine
HAVING COUNT(1) > 2
ORDER BY count(1) DESC
Hlex
sumber
1

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.

Raveesh Badoni
sumber
0

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.

dshiga
sumber
0

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.

gilbertoag.dll
sumber
0

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.

RArora
sumber
Ini menyelamatkan beberapa gejala tetapi tidak benar-benar menyelesaikan masalah. Anda perlu memperbaiki kode Anda sehingga menutup kursor setelah selesai dengan mereka.
APC