java.sql.SQLException: - ORA-01000: vượt quá con trỏ mở tối đa


115

Tôi đang nhận được ngoại lệ SQL ORA-01000. Vì vậy, tôi có một số truy vấn liên quan đến nó.

  1. Các con trỏ mở tối đa có liên quan chính xác đến số lượng kết nối JDBC hay chúng cũng liên quan đến các đối tượng câu lệnh và kết quả mà chúng ta đã tạo cho một kết nối? (Chúng tôi đang sử dụng nhóm kết nối)
  2. Có cách nào để cấu hình số lượng đối tượng statement / resultset trong cơ sở dữ liệu (như các kết nối) không?
  3. Có nên sử dụng đối tượng câu lệnh / resultset biến đối tượng thay vì đối tượng câu lệnh / kết quả cục bộ phương thức trong một môi trường luồng đơn không?
  4. Việc thực hiện một tuyên bố chuẩn bị trong một vòng lặp gây ra vấn đề này? (Tất nhiên, tôi có thể đã sử dụng sqlBatch) Lưu ý: pStmt bị đóng khi vòng lặp kết thúc.

    { //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. Điều gì sẽ xảy ra nếu Conn.createStatement () và Conn.prepareStatement (sql) được gọi nhiều lần trên một đối tượng kết nối?

Edit1: 6. Việc sử dụng đối tượng câu lệnh tham chiếu Weak / Soft có giúp ngăn ngừa rò rỉ không?

Edit2: 1. Có cách nào khác, tôi có thể tìm thấy tất cả các "statement.close ()" bị thiếu trong dự án của mình không? Tôi hiểu nó không phải là một bộ nhớ bị rò rỉ. Nhưng tôi cần tìm một tham chiếu câu lệnh (trong đó close () không được thực hiện) đủ điều kiện để thu gom rác? Bất kỳ công cụ có sẵn? Hay tôi phải phân tích nó bằng tay?

Xin hãy giúp tôi hiểu nó.

Giải pháp

Để tìm con trỏ đã mở trong Oracle DB cho tên người dùng -VELU

Đi đến máy ORACLE và bắt đầu sqlplus dưới dạng sysdba.

[oracle@db01 ~]$ sqlplus / as sysdba 

Sau đó chạy

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

Nếu có thể xin vui lòng đọc câu trả lời của tôi để hiểu thêm về giải pháp của tôi


Bạn có thể gửi mã hoàn chỉnh của bạn? Sẽ rất thú vị khi xem bạn đóng cửa niềng răng mở ở đâufor (String language : additionalLangs) {
Jåcob

@ Kanagavelu Sugumar: tại sao không hỏi 5 câu hỏi khác nhau trong SO?
Jayan

1
Đây là một phản hồi tôi thấy rất hữu ích: stackoverflow.com/a/4507507/501113
chaotic3quilibrium

Vui lòng xem câu trả lời có hữu ích không: stackoverflow.com/questions/34716456/ từ
Manu

Để theo dõi các con trỏ mở trong Oracle, bạn cũng có thể muốn xem qua SYS.V$OPEN_CURSORchế độ xem. Điều này sẽ cung cấp cho bạn không chỉ SID, mà cả văn bản SQL.
Bass

Câu trả lời:


290

ORA-01000, lỗi con trỏ mở tối đa, là một lỗi cực kỳ phổ biến trong phát triển cơ sở dữ liệu của Oracle. Trong ngữ cảnh của Java, nó xảy ra khi ứng dụng cố gắng mở nhiều Kết quả hơn là các con trỏ được cấu hình trên một cá thể cơ sở dữ liệu.

Nguyên nhân phổ biến là:

  1. Lỗi cấu hình

    • Bạn có nhiều luồng trong ứng dụng của mình truy vấn cơ sở dữ liệu hơn các con trỏ trên DB. Một trường hợp là nơi bạn có một kết nối và nhóm luồng lớn hơn số lượng con trỏ trên cơ sở dữ liệu.
    • Bạn có nhiều nhà phát triển hoặc ứng dụng được kết nối với cùng một thể hiện DB (có thể sẽ bao gồm nhiều lược đồ) và cùng nhau bạn đang sử dụng quá nhiều kết nối.
    • Giải pháp:

      • Tăng số lượng con trỏ trên cơ sở dữ liệu (nếu tài nguyên cho phép) hoặc
      • Giảm số lượng chủ đề trong ứng dụng.
  2. Rò rỉ con trỏ

    • Các ứng dụng không đóng resultSets (trong JDBC) hoặc con trỏ (trong các thủ tục được lưu trữ trên cơ sở dữ liệu)
    • Giải pháp : Rò rỉ con trỏ là lỗi; tăng số lượng con trỏ trên DB chỉ đơn giản là trì hoãn sự thất bại không thể tránh khỏi. Rò rỉ có thể được tìm thấy bằng cách sử dụng phân tích mã tĩnh , JDBC hoặc ghi nhật ký cấp ứng dụng và giám sát cơ sở dữ liệu .

Lý lịch

Phần này mô tả một số lý thuyết đằng sau các con trỏ và cách sử dụng JDBC. Nếu bạn không cần biết nền, bạn có thể bỏ qua phần này và đi thẳng đến 'Loại bỏ rò rỉ'.

Một con trỏ là gì?

Con trỏ là một tài nguyên trên cơ sở dữ liệu chứa trạng thái của truy vấn, cụ thể là vị trí mà trình đọc nằm trong Bộ kết quả. Mỗi câu lệnh SELECT có một con trỏ và các thủ tục được lưu trữ PL / SQL có thể mở và sử dụng nhiều con trỏ theo yêu cầu. Bạn có thể tìm hiểu thêm về các con trỏ trên Orafaq .

Một phiên bản cơ sở dữ liệu thường phục vụ một số lược đồ khác nhau , nhiều người dùng khác nhau, mỗi phiênnhiều phiên . Để làm điều này, nó có một số con trỏ cố định có sẵn cho tất cả các lược đồ, người dùng và phiên. Khi tất cả các con trỏ đang mở (đang sử dụng) và yêu cầu xuất hiện yêu cầu một con trỏ mới, yêu cầu không thành công với lỗi ORA-010000.

Tìm và thiết lập số lượng con trỏ

Số thường được cấu hình bởi DBA khi cài đặt. Số lượng con trỏ hiện đang sử dụng, số lượng tối đa và cấu hình có thể được truy cập trong các chức năng Quản trị viên trong Oracle SQL Developer . Từ SQL, nó có thể được đặt bằng:

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

Liên kết JDBC trong JVM với các con trỏ trên DB

Các đối tượng JDBC bên dưới được liên kết chặt chẽ với các khái niệm cơ sở dữ liệu sau:

  • Kết nối JDBC là đại diện khách hàng của phiên cơ sở dữ liệu và cung cấp các giao dịch cơ sở dữ liệu . Một kết nối chỉ có thể mở một giao dịch duy nhất tại một thời điểm (nhưng các giao dịch có thể được lồng nhau)
  • Một JDBC ResultSet được hỗ trợ bởi một đơn trỏ trên cơ sở dữ liệu. Khi close () được gọi trên Kết quả, con trỏ sẽ được giải phóng.
  • Một CallableStatement của JDBC gọi một thủ tục được lưu trữ trên cơ sở dữ liệu, thường được viết bằng PL / SQL. Quy trình được lưu trữ có thể tạo ra 0 hoặc nhiều con trỏ và có thể trả về một con trỏ dưới dạng Bộ kết quả JDBC.

JDBC là luồng an toàn: Việc truyền các đối tượng JDBC khác nhau giữa các luồng là khá ổn.

Ví dụ: bạn có thể tạo kết nối trong một luồng; một luồng khác có thể sử dụng kết nối này để tạo PreparedStatement và luồng thứ ba có thể xử lý tập kết quả. Hạn chế chính duy nhất là bạn không thể mở nhiều Kết quả trên một PreparedStatement duy nhất bất cứ lúc nào. Xem Oracle DB có hỗ trợ nhiều hoạt động (song song) cho mỗi kết nối không?

Lưu ý rằng một cam kết cơ sở dữ liệu xảy ra trên một Kết nối và do đó, tất cả các DML (CHERTN, CẬP NHẬT và XÓA) trên kết nối đó sẽ cùng nhau cam kết. Do đó, nếu bạn muốn hỗ trợ nhiều giao dịch cùng một lúc, bạn phải có ít nhất một Kết nối cho mỗi Giao dịch đồng thời.

Đóng các đối tượng JDBC

Một ví dụ điển hình của việc thực hiện một Kết quả là:

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

Lưu ý cách mệnh đề cuối cùng bỏ qua mọi ngoại lệ được đưa ra bởi close ():

  • Nếu bạn chỉ đơn giản đóng Kết quả mà không thử {} bắt {}, nó có thể thất bại và ngăn Tuyên bố bị đóng
  • Chúng tôi muốn cho phép bất kỳ ngoại lệ nào được nêu ra trong cơ thể của cố gắng tuyên truyền cho người gọi. Nếu bạn có một vòng lặp, ví dụ, tạo và thực thi các Báo cáo, hãy nhớ đóng từng Tuyên bố trong vòng lặp.

Trong Java 7, Oracle đã giới thiệu giao diện AutoClosizable thay thế hầu hết các bản tóm tắt Java 6 bằng một số đường cú pháp hay.

Giữ các đối tượng JDBC

Các đối tượng JDBC có thể được giữ an toàn trong các biến cục bộ, thể hiện đối tượng và các thành viên lớp. Nói chung là thực hành tốt hơn để:

  • Sử dụng cá thể đối tượng hoặc thành viên lớp để giữ các đối tượng JDBC được sử dụng lại nhiều lần trong một khoảng thời gian dài hơn, chẳng hạn như Kết nối và PreparedStatements
  • Sử dụng các biến cục bộ cho resultSets vì chúng được lấy, lặp đi lặp lại và sau đó đóng thường trong phạm vi của một hàm duy nhất.

Tuy nhiên, có một ngoại lệ: Nếu bạn đang sử dụng EJB hoặc thùng chứa Servlet / JSP, bạn phải tuân theo một mô hình luồng nghiêm ngặt:

  • Chỉ Máy chủ ứng dụng tạo các luồng (mà nó xử lý các yêu cầu đến)
  • Chỉ Máy chủ ứng dụng tạo kết nối (mà bạn có được từ nhóm kết nối)
  • Khi lưu các giá trị (trạng thái) giữa các cuộc gọi, bạn phải rất cẩn thận. Không bao giờ lưu trữ giá trị trong bộ nhớ cache hoặc thành viên tĩnh của bạn - điều này không an toàn trên các cụm và các điều kiện kỳ ​​lạ khác và Máy chủ ứng dụng có thể làm những điều khủng khiếp đối với dữ liệu của bạn. Thay vào đó sử dụng đậu trạng thái hoặc cơ sở dữ liệu.
  • Cụ thể, không bao giờ giữ các đối tượng JDBC (Kết nối, Kết quả, PreparedStatements, v.v.) trên các yêu cầu từ xa khác nhau - hãy để Máy chủ ứng dụng quản lý việc này. Máy chủ ứng dụng không chỉ cung cấp một nhóm kết nối, nó còn lưu trữ PreparedStatements của bạn.

Loại bỏ rò rỉ

Có một số quy trình và công cụ có sẵn để giúp phát hiện và loại bỏ rò rỉ JDBC:

  1. Trong quá trình phát triển - bắt lỗi sớm là cách tiếp cận tốt nhất:

    1. Thực tiễn phát triển: Thực tiễn phát triển tốt sẽ làm giảm số lượng lỗi trong phần mềm của bạn trước khi nó rời khỏi bàn của nhà phát triển. Thực hành cụ thể bao gồm:

      1. Lập trình cặp , để giáo dục những người không có đủ kinh nghiệm
      2. Mã đánh giá vì nhiều mắt tốt hơn một
      3. Kiểm thử đơn vị có nghĩa là bạn có thể thực hiện bất kỳ và tất cả các cơ sở mã của mình từ một công cụ kiểm tra khiến việc sao chép rò rỉ trở nên tầm thường
      4. Sử dụng các thư viện hiện có để tổng hợp kết nối thay vì xây dựng thư viện của riêng bạn
    2. Phân tích mã tĩnh: Sử dụng một công cụ như Findbugs xuất sắc để thực hiện phân tích mã tĩnh. Điều này chọn nhiều nơi mà đóng () chưa được xử lý chính xác. Findbugs có một plugin cho Eclipse, nhưng nó cũng chạy độc lập cho một lần, có tích hợp vào Jenkins CI và các công cụ xây dựng khác

  2. Trong thời gian chạy:

    1. Khả năng giữ và cam kết

      1. Nếu khả năng giữ kết quả của Bộ kết quả là Kết quả Bộ. Điều này có thể được đặt bằng cách sử dụng Connection.setHoldability () hoặc bằng cách sử dụng phương thức Connection.createStatement () bị quá tải.
    2. Đăng nhập vào thời gian chạy.

      1. Đặt báo cáo nhật ký tốt trong mã của bạn. Những điều này nên rõ ràng và dễ hiểu để khách hàng, nhân viên hỗ trợ và đồng đội có thể hiểu mà không cần đào tạo. Chúng nên ngắn gọn và bao gồm in các giá trị trạng thái / nội bộ của các biến và thuộc tính chính để bạn có thể theo dõi logic xử lý. Ghi nhật ký tốt là cơ bản để gỡ lỗi các ứng dụng, đặc biệt là những ứng dụng đã được triển khai.
      2. Bạn có thể thêm trình điều khiển JDBC gỡ lỗi vào dự án của mình (để gỡ lỗi - không thực sự triển khai nó). Một ví dụ (tôi chưa sử dụng nó) là log4jdbc . Sau đó, bạn cần thực hiện một số phân tích đơn giản trên tệp này để xem những người thực thi nào không có lần đóng tương ứng. Đếm mở và đóng sẽ làm nổi bật nếu có vấn đề tiềm ẩn

        1. Giám sát cơ sở dữ liệu. Giám sát ứng dụng đang chạy của bạn bằng các công cụ, chẳng hạn như chức năng 'Giám sát SQL' của Nhà phát triển SQL hoặc TOAD của Quest . Giám sát được mô tả trong bài viết này . Trong quá trình theo dõi, bạn truy vấn các con trỏ mở (ví dụ từ bảng v $ sesstat) và xem lại SQL của chúng. Nếu số lượng con trỏ ngày càng tăng và (quan trọng nhất) bị chi phối bởi một câu lệnh SQL giống hệt nhau, bạn biết rằng bạn có một rò rỉ với SQL đó. Tìm kiếm mã của bạn và xem xét.

Những suy nghĩ khác

Bạn có thể sử dụng WeakReferences để xử lý các kết nối đóng không?

Tham chiếu yếu và mềm là các cách cho phép bạn tham chiếu một đối tượng theo cách cho phép JVM thu gom rác tham chiếu bất cứ lúc nào nó thấy phù hợp (giả sử không có chuỗi tham chiếu mạnh đến đối tượng đó).

Nếu bạn chuyển ReferenceQueue trong hàm tạo cho Reference hoặc mềm, đối tượng được đặt trong ReferenceQueue khi đối tượng được GC'ed khi nó xảy ra (nếu nó xảy ra). Với phương pháp này, bạn có thể tương tác với quyết toán của đối tượng và bạn có thể đóng hoặc hoàn thiện đối tượng tại thời điểm đó.

Tài liệu tham khảo Phantom là một chút kỳ lạ; Mục đích của chúng chỉ là để kiểm soát quyết toán, nhưng bạn không bao giờ có thể có được một tham chiếu đến đối tượng ban đầu, vì vậy sẽ rất khó để gọi phương thức close () trên nó.

Tuy nhiên, hiếm khi nên cố gắng kiểm soát khi GC chạy (Weak, Soft và PhantomReferences cho bạn biết sau khi thực tế là đối tượng bị mê hoặc bởi GC). Trong thực tế, nếu dung lượng bộ nhớ trong JVM lớn (ví dụ -Xmx2000m), bạn có thể không bao giờ sử dụng đối tượng và bạn vẫn sẽ trải nghiệm ORA-01000. Nếu bộ nhớ JVM nhỏ so với yêu cầu của chương trình của bạn, bạn có thể thấy rằng các đối tượng result Set và PreparedStatement được xử lý ngay sau khi tạo (trước khi bạn có thể đọc từ chúng), điều đó có thể sẽ làm hỏng chương trình của bạn.

TL; DR: Cơ chế tham chiếu yếu không phải là cách tốt để quản lý và đóng các đối tượng Statement và result Set.


3
Nếu bạn tạo các câu lệnh trong một vòng lặp, hãy chắc chắn rằng nó được đóng trong vòng lặp khác, cuối cùng bạn sẽ chỉ đóng câu lệnh cuối cùng.
basiljames

Cảm ơn, basiljames. Chỉ cần chỉnh sửa câu trả lời để thêm vào điểm bạn đã thực hiện.
Andrew Alcock

@ Andrew Alcock Cảm ơn rất nhiều! Andrew. Bạn có thể vui lòng trả lời thứ 6 cũng được.
Kanagavelu Sugumar

@AndrewAlcock Xin vui lòng .. xin vui lòng .. xin vui lòng .. trả lời câu hỏi thứ 7 của tôi cũng. Vì dự án của chúng tôi, chúng tôi phải đối mặt với ORA-01000 rất thường xuyên trong khi thử tải. Đầu vào của bạn có giá trị hơn đối với tôi. Cảm ơn một tấn trước !!
Kanagavelu Sugumar

RE: 7 - bạn có thể thử tìm kiếm gần bằng cách sử dụng một công cụ như grep. Khi bạn nhận ra SQL (chọn, chèn, cập nhật, xóa), hãy xem khoảng cách gần của từ close () bên cạnh câu lệnh. Nếu khoảng cách gần hơn dự kiến, đó có thể là một cách để điều tra nơi thiếu. lightboxtechnology.com/2012/07/27/ từ
nhật

28

Tôi đang thêm vài sự hiểu biết.

  1. Con trỏ chỉ là về một tuyên bố objecct; Nó không phải là kết quả cũng không phải là đối tượng kết nối.
  2. Nhưng chúng ta vẫn phải đóng tập kết quả để giải phóng bộ nhớ sấm sét. Tuy nhiên, nếu bạn không đóng tập kết quả sẽ không được tính cho HIỆN TẠI.
  3. Đóng đối tượng Statement cũng sẽ tự động đóng đối tượng resultset.
  4. Con trỏ sẽ được tạo cho tất cả các câu lệnh CHỌN / CHERTN / CẬP NHẬT / XÓA.
  5. Mỗi phiên bản ORACLE DB có thể được xác định bằng cách sử dụng SID oracle; tương tự ORACLE DB có thể xác định từng kết nối bằng SID kết nối. Cả SID đều khác nhau.
  6. Vì vậy, phiên ORACLE không có gì ngoài kết nối jdbc (tcp); không có gì ngoài một SID.
  7. Nếu chúng ta đặt các con trỏ tối đa là 500 thì nó chỉ dành cho một phiên / kết nối / SID JDBC.
  8. Vì vậy, chúng ta có thể có nhiều kết nối JDBC với không có con trỏ (câu lệnh) tương ứng.
  9. Khi JVM bị chấm dứt, tất cả các kết nối / con trỏ sẽ bị đóng, HOẶC JDBCConnection bị đóng HIỆN TẠI đối với kết nối đó sẽ bị đóng.

Đăng nhập như sysdba.

Trong Putty (đăng nhập Oracle):

  [oracle@db01 ~]$ sqlplus / as sysdba

Trong SqlPlus:

Tên tài khoản: sys as sysdba

Đặt giá trị session_cached_cursors thành 0 để nó không có con trỏ đóng.

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

Chọn bộ valuse OPEN_CURSORS hiện có cho mỗi kết nối trong 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;

Dưới đây là truy vấn để tìm danh sách SID / kết nối với các giá trị con trỏ mở.

 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'

Sử dụng truy vấn dưới đây để xác định sql's trong các con trỏ mở

 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'

Bây giờ gỡ lỗi Mã và thưởng thức !!! :)


1
Đây là một truy vấn khác có vẻ hoạt động tốt: stackoverflow.com/a/2560415/32453
rogerdpack

4

Sửa mã của bạn như thế này:

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

Bạn có chắc chắn rằng bạn đang thực sự đóng pStatements, kết nối và kết quả của mình không?

Để phân tích các đối tượng mở, bạn có thể mô phỏng một mẫu đại biểu, bao bọc mã xung quanh các đối tượng kết nối, kết nối và kết quả của bạn. Vì vậy, bạn sẽ thấy, nếu một đối tượng sẽ đóng thành công.

Một ví dụ cho: 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

Nếu ứng dụng của bạn là ứng dụng Java EE chạy trên Oracle WebLogic với tư cách là máy chủ ứng dụng, nguyên nhân có thể gây ra sự cố này là cài đặt Kích thước bộ đệm ẩn trong WebLogic.

Nếu cài đặt Kích thước bộ đệm câu lệnh cho một nguồn dữ liệu cụ thể bằng hoặc lớn hơn cài đặt đếm con trỏ mở tối đa của cơ sở dữ liệu Oracle, thì tất cả các con trỏ mở có thể được sử dụng bởi các câu lệnh SQL được lưu trữ được mở bởi WebLogic, dẫn đến trong lỗi ORA-01000.

Để giải quyết vấn đề này, hãy giảm cài đặt Kích thước bộ đệm ẩn cho mỗi nguồn dữ liệu WebLogic trỏ đến cơ sở dữ liệu Oracle nhỏ hơn đáng kể so với cài đặt đếm con trỏ tối đa trên cơ sở dữ liệu.

Trong Bảng điều khiển dành cho quản trị viên WebLogic 10, có thể tìm thấy cài đặt Kích thước bộ đệm ẩn cho mỗi nguồn dữ liệu tại Dịch vụ (điều hướng bên trái)> Nguồn dữ liệu> (nguồn dữ liệu riêng lẻ)> tab Nhóm kết nối.


1
Hibernate cũng có bộ đệm Statement. Xem thêm developer.jboss.org/wiki/
Pino

3

Tôi cũng đã phải đối mặt với vấn đề này. Ngoại lệ dưới đây được sử dụng để đến

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

Tôi đã sử dụng Spring Framework với Spring JDBC cho lớp dao.

Ứng dụng của tôi được sử dụng để rò rỉ con trỏ bằng cách nào đó và sau vài phút hoặc lâu hơn, Nó đã sử dụng để cho tôi ngoại lệ này.

Sau rất nhiều lần gỡ lỗi và phân tích kỹ lưỡng, tôi thấy rằng có vấn đề với Lập chỉ mục, Khóa chính và các ràng buộc duy nhất trong một trong các Bảng được sử dụng trong Truy vấn tôi đang thực hiện.

Ứng dụng của tôi đã cố cập nhật các Cột bị lập chỉ mục nhầm . Vì vậy, bất cứ khi nào ứng dụng của tôi nhấn truy vấn cập nhật trên các cột được lập chỉ mục, Cơ sở dữ liệu sẽ cố gắng thực hiện reindexing dựa trên các giá trị được cập nhật. Nó đã bị rò rỉ các con trỏ .

Tôi đã có thể giải quyết vấn đề bằng cách thực hiện Lập chỉ mục thích hợp trên các cột được sử dụng để tìm kiếm trong truy vấn và áp dụng các ràng buộc thích hợp bất cứ nơi nào cần thiết.


2

Tôi đã đối mặt với cùng một vấn đề (ORA-01000) ngày hôm nay. Tôi đã có một vòng lặp for trong thử {}, để thực thi câu lệnh CHỌN trong Oracle DB nhiều lần, (mỗi lần thay đổi một tham số) và cuối cùng {} tôi đã có mã của mình để đóng resultset, PreparedStatement và Kết nối như bình thường . Nhưng ngay khi tôi đạt được một số vòng lặp cụ thể (1000), tôi đã gặp lỗi Oracle về quá nhiều con trỏ mở.

Dựa trên bài đăng của Andrew Alcock ở trên, tôi đã thực hiện các thay đổi để bên trong vòng lặp, tôi đóng từng kết quả và từng câu lệnh sau khi nhận được dữ liệu và trước khi lặp lại, và điều đó đã giải quyết vấn đề.

Ngoài ra, cùng một vấn đề chính xác xảy ra trong một vòng lặp khác của Câu lệnh chèn, trong một Oracle DB khác (ORA-01000), lần này sau 300 câu lệnh. Một lần nữa, nó đã được giải quyết theo cùng một cách, do đó, PreparedStatement hoặc result Set hoặc cả hai, được tính là con trỏ mở cho đến khi chúng được đóng lại.


Điều này có vẻ không đúng. Các tài liệu về mùa xuân có trách nhiệm đóng các Kết quả ( docs.spring.io/spring/docs/civerse/spring-framework-reference/ trên ).
Ryan

chỉ để làm rõ, trong những ví dụ đó tôi đã không sử dụng Spring.
Kinnison84

1

Bạn đã đặt autocommit = true? Nếu không thử điều này:

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

Bạn có thể vui lòng trả lời các câu hỏi khác là tốt?
Kanagavelu Sugumar

2
Autocommit không đóng kết nối - nó chỉ tự động xác nhận từng câu lệnh ngay sau khi thực thi. Nếu bạn đang sử dụng autocommit, bạn sẽ không nhận được giá trị từ một trong những thuộc tính quan trọng nhất của cơ sở dữ liệu - giao dịch. Bạn có thể cân nhắc sử dụng DB NoQuery thay thế.
Andrew Alcock

1

truy vấn để tìm sql mà mở.

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

Vấn đề này chủ yếu xảy ra khi bạn đang sử dụng nhóm kết nối vì khi bạn đóng kết nối đó sẽ quay lại nhóm kết nối và tất cả con trỏ được liên kết với kết nối đó không bao giờ bị đóng do kết nối với cơ sở dữ liệu vẫn mở. Vì vậy, một cách khác là giảm thời gian kết nối nhàn rỗi của các kết nối trong nhóm, vì vậy có thể bất cứ khi nào kết nối không hoạt động trong 10 giây, kết nối với cơ sở dữ liệu sẽ bị đóng và kết nối mới được tạo để đặt vào nhóm.



0

Trong trường hợp của chúng tôi, chúng tôi đã sử dụng Hibernate và chúng tôi có nhiều biến tham chiếu cùng một thực thể được ánh xạ Hibernate. Chúng tôi đã tạo và lưu các tài liệu tham khảo này trong một vòng lặp. Mỗi tham chiếu đã mở một con trỏ và giữ cho nó mở.

Chúng tôi đã phát hiện ra điều này bằng cách sử dụng truy vấn để kiểm tra số lượng con trỏ mở trong khi chạy mã của chúng tôi, bước qua với trình gỡ lỗi và chọn lọc nhận xét mọi thứ.

Về lý do tại sao mỗi tham chiếu mới mở một con trỏ khác - thực thể được đề cập có các bộ sưu tập của các thực thể khác được ánh xạ tới nó và tôi nghĩ rằng điều này có liên quan đến nó (có lẽ không chỉ riêng nó mà kết hợp với cách chúng tôi đã định cấu hình chế độ tìm nạp và cài đặt bộ đệm). Bản thân Hibernate đã có lỗi xung quanh việc không đóng các con trỏ mở, mặc dù có vẻ như chúng đã được sửa trong các phiên bản sau.

Vì chúng tôi thực sự không cần phải có quá nhiều tài liệu tham khảo trùng lặp cho cùng một thực thể, nên giải pháp là ngừng tạo và giữ tất cả các tài liệu tham khảo dư thừa đó. Một khi chúng tôi đã làm điều đó vấn đề khi đi xa.


0

Tôi gặp vấn đề này với nguồn dữ liệu của mình trong WildFly và Tomcat, kết nối với Oracle 10g.

Tôi thấy rằng trong một số điều kiện, câu lệnh không được đóng ngay cả khi câu lệnh.close () được gọi. Vấn đề là với Trình điều khiển Oracle mà chúng tôi đang sử dụng: ojdbc7.jar. Trình điều khiển này dành cho Oracle 12c và 11g và dường như có một số vấn đề khi được sử dụng với Oracle 10g, vì vậy tôi hạ cấp xuống ojdbc5.jar và bây giờ mọi thứ đang chạy tốt.


0

Tôi gặp phải vấn đề tương tự vì tôi đã truy vấn db hơn 1000 lần lặp. Tôi đã sử dụng thử và cuối cùng trong mã của tôi. Nhưng vẫn nhận được lỗi.

Để giải quyết vấn đề này, tôi chỉ cần đăng nhập vào oracle db và chạy bên dưới truy vấn:

ALTER HỆ THỐNG THIẾT LẬP open_cursors = 8000 SCOPE = BOTH;

Và điều này đã giải quyết vấn đề của tôi ngay lập tức.


Điều này cứu được một số triệu chứng nhưng thực sự không giải quyết được vấn đề. Bạn cần sửa mã của mình để nó đóng các con trỏ một khi nó đã hoàn thành với chúng.
APC
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.