java.sql.SQLException: - ORA-01000: เกินเคอร์เซอร์เปิดสูงสุด


115

ฉันได้รับข้อยกเว้น ORA-01000 SQL ดังนั้นฉันจึงมีคำถามที่เกี่ยวข้องกับมัน

  1. เคอร์เซอร์แบบเปิดสูงสุดเกี่ยวข้องกับจำนวนการเชื่อมต่อ JDBC หรือไม่หรือเกี่ยวข้องกับคำสั่งและวัตถุผลลัพธ์ที่เราสร้างขึ้นสำหรับการเชื่อมต่อเดียวหรือไม่ (เรากำลังใช้กลุ่มการเชื่อมต่อ)
  2. มีวิธีกำหนดค่าจำนวนวัตถุคำสั่ง / ผลลัพธ์ในฐานข้อมูลหรือไม่ (เช่นการเชื่อมต่อ)
  3. แนะนำให้ใช้คำสั่งตัวแปรอินสแตนซ์ / ออบเจ็กต์ผลลัพธ์แทนวิธีโลคัลคำสั่ง / อ็อบเจ็กต์ผลลัพธ์ในสภาพแวดล้อมเธรดเดียวหรือไม่
  4. การดำเนินการคำสั่งที่เตรียมไว้ในลูปทำให้เกิดปัญหานี้หรือไม่ (แน่นอนฉันสามารถใช้ sqlBatch ได้) หมายเหตุ: pStmt ถูกปิดเมื่อลูปสิ้นสุดลง

    { //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. จะเกิดอะไรขึ้นถ้า conn.createStatement () และ conn.prepareStatement (sql) ถูกเรียกหลายครั้งบนอ็อบเจ็กต์การเชื่อมต่อเดียว

Edit1: 6. การใช้วัตถุอ้างอิงอ่อน / อ่อนจะช่วยป้องกันการรั่วไหลได้หรือไม่?

Edit2: 1. มีวิธีใดบ้างที่ฉันสามารถค้นหา "statement.close ()" ที่หายไปทั้งหมดในโครงการของฉันได้หรือไม่? ฉันเข้าใจว่ามันไม่ใช่ความทรงจำที่รั่วไหล แต่ฉันต้องการค้นหาการอ้างอิงคำสั่ง (โดยที่ไม่มีการปิด ()) ที่มีสิทธิ์ได้รับการเก็บขยะ? มีเครื่องมือใดบ้าง หรือฉันต้องวิเคราะห์ด้วยตนเอง?

โปรดช่วยฉันทำความเข้าใจ

สารละลาย

หากต้องการค้นหาเคอร์เซอร์ที่เปิดใน Oracle DB สำหรับชื่อผู้ใช้ -VELU

ไปที่เครื่อง ORACLE และเริ่ม sqlplus เป็น sysdba

[oracle@db01 ~]$ sqlplus / as sysdba 

จากนั้นเรียกใช้

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

ถ้าเป็นไปได้โปรดอ่านคำตอบของฉันเพื่อความเข้าใจมากขึ้นเกี่ยวกับวิธีแก้ปัญหาของฉัน


คุณสามารถโพสต์รหัสทั้งหมดของคุณได้หรือไม่? มันน่าสนใจที่จะเห็นว่าคุณกำลังปิดวงเล็บปีกกาเปิดอยู่for (String language : additionalLangs) {
ที่ไหน

@ Kanagavelu Sugumar: ทำไมไม่ถาม 5 คำถามที่แตกต่างกันใน SO?
Jayan

1
นี่คือคำตอบที่ฉันพบว่ามีประโยชน์มาก: stackoverflow.com/a/4507507/501113
dirty3quilibrium

โปรดดูว่าคำตอบมีประโยชน์หรือไม่: stackoverflow.com/questions/34716456/…
Manu

สำหรับการติดตามเคอร์เซอร์แบบเปิดใน Oracle คุณอาจต้องการดูที่SYS.V$OPEN_CURSORมุมมอง สิ่งนี้จะให้คุณไม่เพียง แต่ SID เท่านั้น แต่ยังรวมถึงข้อความ SQL ด้วย
เบส

คำตอบ:


291

ORA-01000 ข้อผิดพลาดเคอร์เซอร์เปิดสูงสุดเป็นข้อผิดพลาดที่พบบ่อยมากในการพัฒนาฐานข้อมูล Oracle ในบริบทของ Java จะเกิดขึ้นเมื่อแอ็พพลิเคชันพยายามเปิด ResultSets มากกว่าที่กำหนดเคอร์เซอร์บนอินสแตนซ์ฐานข้อมูล

สาเหตุทั่วไปคือ:

  1. ข้อผิดพลาดในการกำหนดค่า

    • คุณมีเธรดในแอ็พพลิเคชันของคุณในการสอบถามฐานข้อมูลมากกว่าเคอร์เซอร์บน DB กรณีหนึ่งคือคุณมีการเชื่อมต่อและเธรดพูลที่มีขนาดใหญ่กว่าจำนวนเคอร์เซอร์บนฐานข้อมูล
    • คุณมีนักพัฒนาหรือแอปพลิเคชันมากมายที่เชื่อมต่อกับอินสแตนซ์ DB เดียวกัน (ซึ่งอาจรวมถึงสคีมาจำนวนมาก) และคุณใช้การเชื่อมต่อร่วมกันมากเกินไป
    • สารละลาย:

  2. เคอร์เซอร์รั่ว

    • แอ็พพลิเคชันไม่ได้ปิด ResultSets (ใน JDBC) หรือเคอร์เซอร์ (ในโพรซีเดอร์ที่เก็บไว้บนฐานข้อมูล)
    • วิธีแก้ไข : การรั่วไหลของเคอร์เซอร์เป็นจุดบกพร่อง การเพิ่มจำนวนเคอร์เซอร์บน DB เพียงแค่ชะลอความล้มเหลวที่หลีกเลี่ยงไม่ได้ การรั่วไหลที่สามารถพบได้โดยใช้การวิเคราะห์รหัสคง , JDBCหรือเข้าสู่ระบบระดับโปรแกรมประยุกต์และการตรวจสอบฐานข้อมูล

พื้นหลัง

ส่วนนี้อธิบายถึงทฤษฎีบางประการที่อยู่เบื้องหลังเคอร์เซอร์และวิธีใช้ JDBC หากคุณไม่จำเป็นต้องรู้พื้นหลังคุณสามารถข้ามสิ่งนี้และตรงไปที่ 'การกำจัดการรั่วไหล'

เคอร์เซอร์คืออะไร?

เคอร์เซอร์เป็นทรัพยากรบนฐานข้อมูลที่เก็บสถานะของแบบสอบถามโดยเฉพาะตำแหน่งที่ผู้อ่านอยู่ใน ResultSet คำสั่ง SELECT แต่ละคำสั่งมีเคอร์เซอร์และโพรซีเดอร์ที่จัดเก็บ PL / SQL สามารถเปิดและใช้เคอร์เซอร์ได้มากเท่าที่ต้องการ คุณสามารถหาข้อมูลเพิ่มเติมเกี่ยวกับเคอร์เซอร์บนOrafaq

อินสแตนซ์ฐานข้อมูลมักจะทำหน้าที่แตกต่างกันหลายสกีมาที่แตกต่างกันหลายผู้ใช้แต่ละคนมีหลายครั้ง ในการดำเนินการนี้จึงมีเคอร์เซอร์จำนวนคงที่สำหรับสคีมาผู้ใช้และเซสชันทั้งหมด เมื่อเคอร์เซอร์ทั้งหมดเปิดอยู่ (ใช้งานอยู่) และมีการร้องขอที่ต้องใช้เคอร์เซอร์ใหม่คำขอจะล้มเหลวด้วยข้อผิดพลาด ORA-010000

การค้นหาและตั้งค่าจำนวนเคอร์เซอร์

โดยปกติ DBA จะกำหนดค่าหมายเลขไว้ในการติดตั้ง จำนวนของเคอร์เซอร์ใช้อยู่ในปัจจุบันจำนวนสูงสุดและการกำหนดค่าที่สามารถเข้าถึงได้ในการทำงานของผู้ดูแลระบบในOracle SQL Developer จาก SQL สามารถตั้งค่าด้วย:

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

เกี่ยวข้องกับ JDBC ใน JVM กับเคอร์เซอร์บน DB

วัตถุ JDBC ด้านล่างเชื่อมโยงอย่างแน่นหนากับแนวคิดฐานข้อมูลต่อไปนี้:

  • JDBC เชื่อมต่อเป็นตัวแทนลูกค้าของฐานข้อมูลเซสชั่นและให้ฐานข้อมูลการทำธุรกรรม การเชื่อมต่อสามารถเปิดธุรกรรมได้เพียงรายการเดียวในแต่ละครั้ง (แต่สามารถซ้อนธุรกรรมได้)
  • JDBC ResultSetได้รับการสนับสนุนโดยเคอร์เซอร์เดียวบนฐานข้อมูล เมื่อเรียก close () บน ResultSet เคอร์เซอร์จะถูกปล่อย
  • JDBC CallableStatementเรียกใช้โพรซีเดอร์ที่เก็บไว้บนฐานข้อมูลซึ่งมักเขียนด้วย PL / SQL กระบวนงานที่เก็บไว้สามารถสร้างเคอร์เซอร์เป็นศูนย์หรือมากกว่าและสามารถส่งคืนเคอร์เซอร์เป็น JDBC ResultSet

JDBC เป็นเธรดที่ปลอดภัย: ค่อนข้างโอเคที่จะส่งผ่านอ็อบเจ็กต์ JDBC ต่างๆระหว่างเธรด

ตัวอย่างเช่นคุณสามารถสร้างการเชื่อมต่อในเธรดเดียว เธรดอื่นสามารถใช้การเชื่อมต่อนี้เพื่อสร้าง PreparedStatement และเธรดที่สามสามารถประมวลผลชุดผลลัพธ์ ข้อ จำกัด หลักประการเดียวคือคุณไม่สามารถเปิด ResultSet ได้มากกว่าหนึ่งรายการบน PreparedStatement เดียวได้ตลอดเวลา โปรดดูOracle DB รองรับการดำเนินการหลายอย่าง (ขนาน) ต่อการเชื่อมต่อหรือไม่

โปรดทราบว่าการคอมมิตฐานข้อมูลเกิดขึ้นบนการเชื่อมต่อดังนั้น DML ทั้งหมด (INSERT, UPDATE และ DELETE) บนการเชื่อมต่อนั้นจะคอมมิตเข้าด้วยกัน ดังนั้นหากคุณต้องการรองรับธุรกรรมหลายรายการในเวลาเดียวกันคุณต้องมีการเชื่อมต่ออย่างน้อยหนึ่งรายการสำหรับแต่ละธุรกรรมพร้อมกัน

การปิดวัตถุ JDBC

ตัวอย่างทั่วไปของการดำเนินการ ResultSet คือ:

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) { }
}

สังเกตว่าประโยคสุดท้ายจะละเว้นข้อยกเว้นใด ๆ ที่เกิดจากการปิด ():

  • หากคุณเพียงแค่ปิด ResultSet โดยไม่ได้ลอง {} catch {} อาจล้มเหลวและป้องกันไม่ให้ Statement ถูกปิด
  • เราต้องการอนุญาตให้มีข้อยกเว้นใด ๆ ที่เกิดขึ้นในเนื้อหาของการพยายามเผยแพร่ไปยังผู้โทร หากคุณมีการวนซ้ำตัวอย่างเช่นการสร้างและดำเนินการคำสั่งอย่าลืมปิดแต่ละคำสั่งภายในลูป

ใน Java 7 นั้น Oracle ได้เปิดตัวอินเทอร์เฟซ AutoCloseableซึ่งแทนที่แผ่นต้นแบบ Java 6 ส่วนใหญ่ด้วยน้ำตาลซินแทติกที่ดี

ถือวัตถุ JDBC

อ็อบเจ็กต์ JDBC สามารถถูกเก็บไว้อย่างปลอดภัยในตัวแปรโลคัลอินสแตนซ์ออบเจ็กต์และสมาชิกคลาส โดยทั่วไปแล้วแนวทางปฏิบัติที่ดีกว่าคือ:

  • ใช้อ็อบเจ็กต์อินสแตนซ์หรือสมาชิกคลาสเพื่อเก็บอ็อบเจ็กต์ JDBC ที่ใช้ซ้ำหลายครั้งในช่วงเวลาที่ยาวนานขึ้นเช่น Connections และ PreparedStatements
  • ใช้ตัวแปรท้องถิ่นสำหรับ ResultSets เนื่องจากได้รับสิ่งเหล่านี้วนซ้ำแล้วปิดโดยทั่วไปภายในขอบเขตของฟังก์ชันเดียว

อย่างไรก็ตามมีข้อยกเว้นประการหนึ่ง: หากคุณใช้ EJB หรือคอนเทนเนอร์ Servlet / JSP คุณต้องทำตามแบบจำลองเธรดที่เข้มงวด:

  • เฉพาะ Application Server เท่านั้นที่สร้างเธรด (ซึ่งจัดการกับคำร้องขอที่เข้ามา)
  • เฉพาะ Application Server เท่านั้นที่สร้างการเชื่อมต่อ (ซึ่งคุณได้รับจากพูลการเชื่อมต่อ)
  • เมื่อบันทึกค่า (สถานะ) ระหว่างการโทรคุณต้องระวังให้มาก อย่าเก็บค่าในแคชของคุณเองหรือสมาชิกแบบคงที่ - สิ่งนี้ไม่ปลอดภัยในคลัสเตอร์และเงื่อนไขแปลก ๆ อื่น ๆ และ Application Server อาจทำสิ่งเลวร้ายกับข้อมูลของคุณ ใช้เมล็ดถั่วหรือฐานข้อมูลแทน
  • โดยเฉพาะอย่างยิ่งอย่าถือวัตถุ JDBC (Connections, ResultSets, PreparedStatements ฯลฯ ) เหนือการเรียกใช้แบบรีโมตที่แตกต่างกัน - ปล่อยให้ Application Server จัดการสิ่งนี้ Application Server ไม่เพียง แต่มีพูลการเชื่อมต่อเท่านั้น แต่ยังเก็บ PreparedStatements ของคุณไว้ด้วย

กำจัดการรั่วไหล

มีกระบวนการและเครื่องมือมากมายสำหรับช่วยตรวจจับและกำจัดการรั่วไหลของ JDBC:

  1. ระหว่างการพัฒนา - การจับจุดบกพร่อง แต่เนิ่นๆเป็นแนวทางที่ดีที่สุด:

    1. แนวทางปฏิบัติในการพัฒนา: แนวทางปฏิบัติในการพัฒนาที่ดีควรลดจำนวนข้อบกพร่องในซอฟต์แวร์ของคุณก่อนที่จะออกจากโต๊ะทำงานของนักพัฒนาซอฟต์แวร์ แนวทางปฏิบัติเฉพาะ ได้แก่ :

      1. จับคู่การเขียนโปรแกรมเพื่อให้ความรู้แก่ผู้ที่ไม่มีประสบการณ์เพียงพอ
      2. โค๊ดรีวิวเพราะตาเยอะดีกว่ากัน
      3. การทดสอบหน่วยซึ่งหมายความว่าคุณสามารถใช้ฐานรหัสใดก็ได้และทั้งหมดจากเครื่องมือทดสอบซึ่งทำให้การรั่วไหลเกิดขึ้นเป็นเรื่องเล็กน้อย
      4. ใช้ไลบรารีที่มีอยู่เพื่อการเชื่อมต่อร่วมกันแทนที่จะสร้างขึ้นเอง
    2. การวิเคราะห์โค้ดแบบคงที่: ใช้เครื่องมือเช่นFindbugs ที่ยอดเยี่ยมเพื่อทำการวิเคราะห์โค้ดแบบคงที่ สิ่งนี้เลือกสถานที่หลายแห่งที่ปิด () ไม่ได้รับการจัดการอย่างถูกต้อง Findbugs มีปลั๊กอินสำหรับ Eclipse แต่ยังทำงานแบบสแตนด์อโลนสำหรับการใช้งานครั้งเดียวมีการรวมเข้ากับ Jenkins CI และเครื่องมือสร้างอื่น ๆ

  2. ที่รันไทม์:

    1. ความสามารถในการถือครองและการกระทำ

      1. ถ้าความสามารถในการถือครอง ResultSet เป็น ResultSet.CLOSE_CURSORS_OVER_COMMIT ดังนั้น ResultSet จะปิดเมื่อมีการเรียกวิธี Connection.commit () สามารถตั้งค่าได้โดยใช้ Connection.setHoldability () หรือโดยใช้เมธอด Connection.createStatement () ที่โอเวอร์โหลด
    2. เข้าสู่ระบบที่รันไทม์

      1. ใส่ข้อความบันทึกที่ดีในรหัสของคุณ สิ่งเหล่านี้ควรชัดเจนและเข้าใจได้เพื่อให้ลูกค้าพนักงานสนับสนุนและเพื่อนร่วมทีมเข้าใจได้โดยไม่ต้องฝึกอบรม ควรสั้นและรวมถึงการพิมพ์ค่าสถานะ / ภายในของตัวแปรและแอตทริบิวต์หลักเพื่อให้คุณสามารถติดตามตรรกะการประมวลผลได้ การบันทึกที่ดีเป็นพื้นฐานในการดีบักแอปพลิเคชันโดยเฉพาะอย่างยิ่งที่ได้รับการปรับใช้
      2. คุณสามารถเพิ่มไดรเวอร์ JDBC การดีบักลงในโปรเจ็กต์ของคุณ (สำหรับการดีบัก - อย่าปรับใช้จริง) ตัวอย่างหนึ่ง (ผมไม่ได้ใช้มัน) เป็นlog4jdbc จากนั้นคุณต้องทำการวิเคราะห์ง่ายๆในไฟล์นี้เพื่อดูว่าการดำเนินการใดที่ไม่มีการปิดที่เกี่ยวข้อง การนับการเปิดและปิดควรเน้นว่ามีปัญหาหรือไม่

        1. การตรวจสอบฐานข้อมูล ตรวจสอบโปรแกรมที่ทำงานของคุณโดยใช้เครื่องมือเช่น SQL Developer ฟังก์ชั่น 'จอภาพ SQL หรือคางคกเควส การตรวจสอบที่อธิบายไว้ในบทความนี้ ในระหว่างการตรวจสอบคุณสอบถามเคอร์เซอร์แบบเปิด (เช่นจากตาราง v $ sesstat) และตรวจสอบ SQL ของพวกเขา หากจำนวนเคอร์เซอร์เพิ่มขึ้นและ (ที่สำคัญที่สุด) ถูกครอบงำโดยคำสั่ง SQL ที่เหมือนกันคุณจะรู้ว่า SQL รั่ว ค้นหารหัสของคุณและตรวจสอบ

ความคิดอื่น ๆ

คุณสามารถใช้ WeakReferences เพื่อจัดการการปิดการเชื่อมต่อได้หรือไม่?

การอ้างอิงที่อ่อนแอและนุ่มนวลเป็นวิธีที่ช่วยให้คุณสามารถอ้างอิงวัตถุในลักษณะที่อนุญาตให้ JVM เก็บขยะรวบรวมข้อมูลอ้างอิงได้ตลอดเวลาที่เห็นว่าเหมาะสม (สมมติว่าไม่มีโซ่อ้างอิงที่รัดกุมสำหรับวัตถุนั้น)

หากคุณส่ง ReferenceQueue ในคอนสตรัคเตอร์ไปยังการอ้างอิงที่อ่อนหรืออ่อนวัตถุจะถูกวางไว้ใน ReferenceQueue เมื่อวัตถุถูก GC'ed เมื่อเกิดขึ้น (หากเกิดขึ้นเลย) ด้วยวิธีนี้คุณสามารถโต้ตอบกับการสรุปของวัตถุและคุณสามารถปิดหรือสิ้นสุดวัตถุได้ในขณะนั้น

การอ้างอิงของ Phantom ค่อนข้างแปลกกว่า วัตถุประสงค์ของพวกเขาคือเพียงเพื่อควบคุมการสรุป แต่คุณไม่สามารถรับการอ้างอิงไปยังวัตถุดั้งเดิมได้ดังนั้นจึงเป็นการยากที่จะเรียกเมธอด close () บนมัน

อย่างไรก็ตามไม่ค่อยเป็นความคิดที่ดีที่จะพยายามควบคุมเมื่อ GC ทำงาน (Weak, Soft และ PhantomReferences แจ้งให้คุณทราบหลังจากที่วัตถุนั้นถูกกำหนดไว้สำหรับ GC) ในความเป็นจริงหากจำนวนหน่วยความจำใน JVM มีขนาดใหญ่ (เช่น -Xmx2000m) คุณอาจไม่เคย GC วัตถุและคุณจะยังคงได้สัมผัสกับ ORA-01000 หากหน่วยความจำ JVM มีขนาดเล็กเมื่อเทียบกับข้อกำหนดของโปรแกรมของคุณคุณอาจพบว่าอ็อบเจ็กต์ ResultSet และ PreparedStatement เป็น GCed ทันทีหลังจากสร้าง (ก่อนที่คุณจะสามารถอ่านได้) ซึ่งอาจทำให้โปรแกรมของคุณล้มเหลว

TL; DR:กลไกการอ้างอิงที่อ่อนแอไม่ใช่วิธีที่ดีในการจัดการและปิดวัตถุ Statement และ ResultSet


3
หากคุณสร้างคำสั่งแบบวนซ้ำตรวจสอบให้แน่ใจว่ามันถูกปิดในลูปมิฉะนั้นคุณจะจบลงด้วยการปิดเฉพาะคำสั่งสุดท้าย
Basiljames

ขอบคุณ Basiljames เพิ่งแก้ไขคำตอบเพื่อเพิ่มในจุดที่คุณทำ
Andrew Alcock

@ Andrew Alcock ขอบคุณมาก! แอนดรู คุณช่วยตอบข้อ 6 ด้วยได้ไหม
Kanagavelu Sugumar

@AndrewAlcock ได้โปรด .. ได้โปรด .. ได้โปรด .. ตอบคำถามที่ 7 ของฉันด้วย เนื่องจากโครงการของเราเราต้องเผชิญกับ ORA-01000 บ่อยมากในขณะทดสอบโหลด ปัจจัยการผลิตของคุณมีค่ามากขึ้นสำหรับฉัน ขอบคุณล่วงหน้าครับ !!
Kanagavelu Sugumar

RE: 7 - คุณสามารถลองค้นหาความใกล้เคียงโดยใช้เครื่องมือเช่น grep เมื่อคุณรู้จัก SQL (เลือกแทรกอัพเดตลบ) ให้ดูความใกล้เคียงของคำว่า close () ถัดจากคำสั่ง หากความใกล้ชิดอยู่ไกลกว่าที่คาดไว้นั่นอาจเป็นวิธีตรวจสอบว่าหายไปไหน lightboxtechnologies.com/2012/07/27/...
อาทิตย์

28

ฉันกำลังเพิ่มความเข้าใจอีกเล็กน้อย

  1. เคอร์เซอร์เป็นเพียงเกี่ยวกับคำสั่ง objecct; ไม่ใช่ทั้ง resultSet หรือวัตถุการเชื่อมต่อ
  2. แต่เรายังต้องปิดชุดผลลัพธ์เพื่อเพิ่มหน่วยความจำ oracle หากคุณไม่ปิดชุดผลลัพธ์ที่จะไม่ถูกนับเป็น CURSORS
  3. วัตถุปิดคำสั่งจะปิดวัตถุผลลัพธ์โดยอัตโนมัติด้วย
  4. เคอร์เซอร์จะถูกสร้างขึ้นสำหรับคำสั่ง SELECT / INSERT / UPDATE / DELETE ทั้งหมด
  5. แต่ละอินสแตนซ์ ORACLE DB สามารถระบุได้โดยใช้ oracle SID ในทำนองเดียวกัน ORACLE DB สามารถระบุการเชื่อมต่อแต่ละรายการโดยใช้ SID การเชื่อมต่อ SID ทั้งสองแตกต่างกัน
  6. ดังนั้นเซสชัน ORACLE จึงไม่มีอะไรนอกจากการเชื่อมต่อ jdbc (tcp) ซึ่งไม่มีอะไรนอกจาก SID เดียว
  7. หากเราตั้งค่าเคอร์เซอร์สูงสุดเป็น 500 แสดงว่าเป็นเพียงหนึ่งเซสชัน / การเชื่อมต่อ JDBC / SID เท่านั้น
  8. ดังนั้นเราจึงสามารถมีการเชื่อมต่อ JDBC จำนวนมากโดยไม่มีเคอร์เซอร์ตามลำดับ (คำสั่ง)
  9. เมื่อสิ้นสุด JVM แล้วการเชื่อมต่อ / เคอร์เซอร์ทั้งหมดจะถูกปิดหรือการเชื่อมต่อ JDBCC ถูกปิด CURSORS เกี่ยวกับการเชื่อมต่อนั้นจะถูกปิด

Loggin เป็น sysdba

ใน Putty (เข้าสู่ระบบ Oracle):

  [oracle@db01 ~]$ sqlplus / as sysdba

ใน SqlPlus:

ชื่อผู้ใช้: sys as sysdba

ตั้งค่า session_cached_cursors เป็น 0 เพื่อไม่ให้มีเคอร์เซอร์ปิด

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

เลือกชุดค่า OPEN_CURSORS ที่มีอยู่ต่อการเชื่อมต่อใน 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;

ด้านล่างนี้คือแบบสอบถามเพื่อค้นหารายการ SID / การเชื่อมต่อที่มีค่าเคอร์เซอร์เปิด

 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'

ใช้แบบสอบถามด้านล่างเพื่อระบุ sql ในเคอร์เซอร์ที่เปิดอยู่

 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'

ตอนนี้แก้ปัญหารหัสและสนุก !!! :)


1
นี่คือคำค้นหาอื่นที่ดูเหมือนว่าจะทำงานได้ดี: stackoverflow.com/a/2560415/32453
rogerdpack

4

แก้ไขรหัสของคุณดังนี้:

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()
} 

คุณแน่ใจหรือว่าคุณกำลังปิด pStatements การเชื่อมต่อและผลลัพธ์จริงๆ?

ในการวิเคราะห์ออบเจ็กต์ที่เปิดอยู่คุณสามารถแทรกรูปแบบตัวแทนซึ่งล้อมรอบโค้ดรอบ ๆ ตัวกำหนดสถานะการเชื่อมต่อและอ็อบเจ็กต์ผลลัพธ์ คุณจะเห็นว่าวัตถุจะปิดสำเร็จหรือไม่

ตัวอย่างสำหรับ: 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");
        }
    }
}

3

หากแอปพลิเคชันของคุณเป็นแอ็พพลิเคชัน Java EE ที่ทำงานบน Oracle WebLogic เป็นแอ็พพลิเคชันเซิร์ฟเวอร์สาเหตุที่เป็นไปได้สำหรับปัญหานี้คือการตั้งค่าStatement Cache Sizeใน WebLogic

หากการตั้งค่าขนาดแคชคำชี้แจงสำหรับแหล่งข้อมูลหนึ่ง ๆ มีค่าเท่ากับหรือมากกว่าการตั้งค่าจำนวนเคอร์เซอร์ที่เปิดสูงสุดของฐานข้อมูล Oracle ดังนั้นเคอร์เซอร์ที่เปิดทั้งหมดจะถูกใช้โดยคำสั่ง SQL ที่แคชซึ่ง WebLogic เปิดค้างไว้ส่งผลให้ ในข้อผิดพลาด ORA-01000

เพื่อแก้ไขปัญหานี้ให้ลดการตั้งค่าขนาดแคชคำชี้แจงสำหรับแหล่งข้อมูล WebLogic แต่ละแหล่งที่ชี้ไปยังฐานข้อมูล Oracle ให้น้อยกว่าการตั้งค่าจำนวนเคอร์เซอร์สูงสุดบนฐานข้อมูลอย่างมาก

ในคอนโซลผู้ดูแลระบบ WebLogic 10 การตั้งค่าขนาดแคชคำชี้แจงสำหรับแหล่งข้อมูลแต่ละแหล่งสามารถพบได้ที่แท็บ Services (แถบนำทางด้านซ้าย)> แหล่งข้อมูล> (แหล่งข้อมูลแต่ละรายการ)> แท็บพูลการเชื่อมต่อ


1
ไฮเบอร์เนตมีแคชคำชี้แจงด้วย ดูdeveloper.jboss.org/wiki/…
Pino

3

ฉันก็ประสบปัญหานี้เช่นกันข้อยกเว้นด้านล่างเคยมา

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

ฉันใช้Spring FrameworkกับSpring JDBCสำหรับเลเยอร์ dao

แอปพลิเคชันของฉันเคยทำเคอร์เซอร์รั่วและหลังจากนั้นไม่กี่นาทีก็เคยให้ข้อยกเว้นนี้แก่ฉัน

หลังจากการดีบักและการวิเคราะห์อย่างละเอียดถี่ถ้วนฉันพบว่ามีปัญหากับการจัดทำดัชนีคีย์หลักและข้อ จำกัด เฉพาะในตารางที่ใช้ในแบบสอบถามที่ฉันกำลังดำเนินการ

ใบสมัครของฉันได้พยายามที่จะปรับปรุงคอลัมน์ซึ่งเป็นความผิดพลาดที่จัดทำดัชนี ดังนั้นเมื่อใดก็ตามที่แอปพลิเคชันของฉันกดปุ่มคิวรีอัปเดตในคอลัมน์ที่จัดทำดัชนีฐานข้อมูลจะพยายามทำดัชนีซ้ำตามค่าที่อัปเดต มันก็รั่วเคอร์เซอร์

ฉันสามารถแก้ปัญหาได้โดยการทำดัชนีที่เหมาะสมกับคอลัมน์ที่ใช้ในการค้นหาในแบบสอบถามและใช้ข้อ จำกัด ที่เหมาะสมในทุกที่ที่ต้องการ


2

วันนี้ฉันประสบปัญหาเดียวกัน (ORA-01000) ฉันมี for loop ในการลอง {} เพื่อเรียกใช้คำสั่ง SELECT ใน Oracle DB หลายครั้ง (ทุกครั้งที่เปลี่ยนพารามิเตอร์) และในที่สุด {} ฉันก็มีรหัสเพื่อปิด Resultset, PreparedStatement และ Connection ตามปกติ . แต่ทันทีที่ฉันไปถึงจำนวนลูปที่กำหนด (1,000) ฉันได้รับข้อผิดพลาด Oracle เกี่ยวกับเคอร์เซอร์ที่เปิดมากเกินไป

จากโพสต์ของ Andrew Alcock ข้างต้นฉันได้ทำการเปลี่ยนแปลงเพื่อให้ภายในลูปฉันปิดแต่ละชุดผลลัพธ์และแต่ละคำสั่งหลังจากได้รับข้อมูลและก่อนที่จะวนซ้ำอีกครั้งและนั่นช่วยแก้ปัญหาได้

นอกจากนี้ปัญหาเดียวกันที่เกิดขึ้นในการวนซ้ำของคำสั่งแทรกอื่นใน Oracle DB (ORA-01000) ครั้งนี้หลังจากคำสั่ง 300 อีกครั้งได้รับการแก้ไขในลักษณะเดียวกันดังนั้น PreparedStatement หรือ ResultSet หรือทั้งสองอย่างจะนับเป็นเคอร์เซอร์เปิดจนกว่าจะปิด


ดูเหมือนจะไม่ถูกต้อง Spring เอกสารที่รับผิดชอบในการปิด ResultSets ( docs.spring.io/spring/docs/current/spring-framework-reference/… )
Ryan

เพื่อความกระจ่างในตัวอย่างเหล่านั้นฉันไม่ได้ใช้ Spring
Kinnison84

1

คุณตั้งค่า autocommit = true หรือไม่? หากไม่ลองทำดังนี้

{ //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 

คุณช่วยตอบคำถามอื่น ๆ ด้วยได้ไหม
Kanagavelu Sugumar

2
Autocommit ไม่ได้ปิดการเชื่อมต่อ แต่จะส่งคำสั่งแต่ละคำสั่งโดยอัตโนมัติทันทีหลังจากดำเนินการ หากคุณใช้ autocommit คุณจะไม่ได้รับค่าจากคุณสมบัติที่สำคัญที่สุดของฐานข้อมูลนั่นคือธุรกรรม คุณอาจพิจารณาใช้ NoSQL DB แทน
Andrew Alcock

1

แบบสอบถามเพื่อค้นหา sql ที่เปิดขึ้น

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

1

ปัญหานี้ส่วนใหญ่เกิดขึ้นเมื่อคุณใช้การเชื่อมต่อร่วมกันเนื่องจากเมื่อคุณปิดการเชื่อมต่อนั้นการเชื่อมต่อจะกลับไปที่พูลการเชื่อมต่อและเคอร์เซอร์ทั้งหมดที่เกี่ยวข้องกับการเชื่อมต่อนั้นจะไม่ถูกปิดเนื่องจากการเชื่อมต่อกับฐานข้อมูลยังคงเปิดอยู่ ดังนั้นอีกทางเลือกหนึ่งคือการลดเวลาการเชื่อมต่อที่ไม่ได้ใช้งานของการเชื่อมต่อในพูลดังนั้นเมื่อใดก็ตามที่การเชื่อมต่อไม่ได้ใช้งานในการเชื่อมต่อเป็นเวลา 10 วินาทีการเชื่อมต่อกับฐานข้อมูลจะถูกปิดและการเชื่อมต่อใหม่ที่สร้างขึ้นเพื่อใส่ในพูล



0

ในกรณีของเราเราใช้ Hibernate และเรามีตัวแปรมากมายที่อ้างอิงเอนทิตีที่แมป Hibernate เดียวกัน เรากำลังสร้างและบันทึกข้อมูลอ้างอิงเหล่านี้แบบวนซ้ำ การอ้างอิงแต่ละรายการจะเปิดเคอร์เซอร์และเปิดไว้

เราค้นพบสิ่งนี้โดยใช้แบบสอบถามเพื่อตรวจสอบจำนวนเคอร์เซอร์ที่เปิดอยู่ในขณะที่เรียกใช้โค้ดของเราก้าวผ่านตัวแก้ไขข้อบกพร่องและเลือกแสดงความคิดเห็น

สาเหตุที่การอ้างอิงใหม่แต่ละรายการเปิดเคอร์เซอร์อื่น - เอนทิตีที่เป็นปัญหามีคอลเล็กชันของเอนทิตีอื่นที่แมปไว้และฉันคิดว่าสิ่งนี้เกี่ยวข้องกับมัน (อาจไม่ใช่แค่สิ่งนี้เพียงอย่างเดียว แต่รวมกับวิธีที่เรากำหนดค่าโหมดการดึงข้อมูลและ การตั้งค่าแคช) ไฮเบอร์เนตเองก็มีข้อบกพร่องที่ไม่สามารถปิดได้เคอร์เซอร์แบบเปิดได้แม้ว่าจะดูเหมือนว่าสิ่งเหล่านี้ได้รับการแก้ไขแล้วในเวอร์ชันที่ใหม่กว่า

เนื่องจากเราไม่จำเป็นต้องมีการอ้างอิงซ้ำซ้อนกับเอนทิตีเดียวกันมากนักวิธีแก้ปัญหาคือหยุดสร้างและยึดการอ้างอิงที่ซ้ำซ้อนเหล่านั้นทั้งหมด เมื่อเราทำปัญหานั้นเมื่อไม่อยู่


0

ฉันมีปัญหากับแหล่งข้อมูลใน WildFly และ Tomcat โดยเชื่อมต่อกับ Oracle 10g

ฉันพบว่าภายใต้เงื่อนไขบางประการคำสั่งจะไม่ถูกปิดแม้ว่าจะมีการเรียกใช้ statement.close () ปัญหาเกิดจาก Oracle Driver ที่เราใช้: ojdbc7.jar ไดรเวอร์นี้มีไว้สำหรับ Oracle 12c และ 11g และดูเหมือนว่าจะมีปัญหาบางอย่างเมื่อใช้กับ Oracle 10g ดังนั้นฉันจึงปรับลดรุ่นเป็น ojdbc5.jar และตอนนี้ทุกอย่างทำงานได้ดี


0

ฉันประสบปัญหาเดียวกันเนื่องจากฉันกำลังค้นหาฐานข้อมูลสำหรับการทำซ้ำมากกว่า 1,000 ครั้ง ฉันใช้ try และสุดท้ายในรหัสของฉัน แต่ยังคงได้รับข้อผิดพลาด

ในการแก้ปัญหานี้ฉันเพิ่งเข้าสู่ oracle db และเรียกใช้แบบสอบถามด้านล่าง:

ALTER SYSTEM SET open_cursors = 8000 SCOPE = ทั้งสอง;

และสิ่งนี้ช่วยแก้ปัญหาของฉันได้ทันที


วิธีนี้ช่วยบรรเทาอาการบางอย่าง แต่ไม่สามารถแก้ปัญหาได้จริง คุณต้องแก้ไขโค้ดของคุณเพื่อให้มันปิดเคอร์เซอร์เมื่อเสร็จสิ้น
APC
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.