2009-09-17 4 views
6

Chúng tôi đang sử dụng Spring SimpleJdbcCall để gọi các thủ tục lưu sẵn trong Oracle trả lại con trỏ. Có vẻ như SimpleJdbcCall không đóng con trỏ và sau một thời gian, con trỏ mở tối đa bị vượt quá.ORA-01000: con trỏ mở tối đa vượt quá khi sử dụng Spring SimpleJDBCCall

ORA-01000: maximum open cursors exceeded ; nested exception is java.sql.SQLException: ORA-01000: maximum open cursors exceeded spring 

Có một vài người khác trên diễn đàn đã trải nghiệm điều này nhưng dường như không có câu trả lời. Có vẻ như tôi là một lỗi trong hỗ trợ mùa xuân/oracle.

Lỗi này rất quan trọng và có thể ảnh hưởng đến việc sử dụng Spring JDBC trong tương lai của chúng tôi.

Có ai gặp sự cố - hoặc theo dõi vấn đề với mã Spring hoặc tìm giải pháp tránh được sự cố không?

Chúng tôi đang sử dụng Spring 2.5.6.

Dưới đây là phiên bản mới của mã sử dụng SimpleJdbcCall mà dường như không được đóng cửa một cách chính xác kết quả thiết rằng lợi nhuận proc qua một con trỏ:

... 
SimpleJdbcCall call = new SimpleJdbcCall(dataSource); 

Map params = new HashMap(); 
params.put("remote_user", session.getAttribute("cas_username")); 

Map result = call 
    .withSchemaName("urs") 
    .withCatalogName("ursWeb") 
    .withProcedureName("get_roles") 
    .returningResultSet("rolesCur", new au.edu.une.common.util.ParameterizedMapRowMapper()) 
    .execute(params); 
List roles = (List)result.get("rolesCur") 

Các phiên bản cũ hơn của mã mà không sử dụng Spring JDBC không có vấn đề này:

oracleConnection = dataSource.getConnection(); 
callable = oracleConnection.prepareCall(
     "{ call urs.ursweb.get_roles(?, ?) }" ); 
callable.setString(1, (String)session.getAttribute("cas_username")); 
callable.registerOutParameter (2, oracle.jdbc.OracleTypes.CURSOR); 
callable.execute(); 
ResultSet rset = (ResultSet)callable.getObject(2); 
... do stuff with the result set 
if (rset != null) rset.close(); // Explicitly close the resultset 
if (callable != null) callable.close(); //Close the callable 
if (oracleConnection != null) oracleConnection.close(); //Close the connection 

Dường như Spring JDBC KHÔNG gọi rset.close(). Nếu tôi nhận xét ra rằng dòng trong mã cũ sau đó sau khi thử nghiệm tải chúng tôi nhận được cùng một ngoại lệ cơ sở dữ liệu.

+3

Vui lòng đăng một số mã cho biết cách bạn đang sử dụng SimpleJdbcCall. Thật không may rằng đây là một lỗi trong Spring, và nhiều khả năng là cách bạn đang sử dụng nó, đặc biệt là xem xét cách không chuẩn mà Oracle xử lý các resultset. – skaffman

+1

+1 với skaffman. Nếu bạn không thể tìm ra vấn đề, hãy thử xây dựng một trường hợp thử nghiệm đá rắn trước để báo cáo lỗi tại http://jira.springframework.org/ –

Trả lời

7

Sau nhiều lần kiểm tra, chúng tôi đã khắc phục sự cố này. Nó là một sự kết hợp của cách chúng tôi đã sử dụng khung mùa xuân và khách hàng oracle và DB oracle.Chúng tôi đã tạo ra các SimpleJDBCCalls mới đang sử dụng các cuộc gọi siêu dữ liệu của máy khách JDBC của oracle đã được trả lại dưới dạng các con trỏ không bị đóng và dọn dẹp. Tôi xem đây là một lỗi trong khung công tác Spring JDBC trong cách nó gọi siêu dữ liệu nhưng sau đó không đóng con trỏ. Spring nên sao chép dữ liệu meta ra khỏi con trỏ và đóng nó đúng cách. Tôi đã không làm phiền việc mở một vấn đề jira với mùa xuân bởi vì nếu bạn sử dụng thực hành tốt nhất các lỗi không được trưng bày.

Tinh chỉnh OPEN_CURSORS hoặc bất kỳ thông số nào khác là cách sai để khắc phục sự cố này và chỉ làm chậm sự cố này.

Chúng tôi đã làm việc xung quanh nó/cố định nó bằng cách di chuyển SimpleJDBCCall thành một DAO singleton để chỉ có một con trỏ mở cho mỗi oracle proc mà chúng ta gọi. Những con trỏ này mở ra trong suốt vòng đời của ứng dụng - mà tôi xem là một lỗi. Miễn là OPEN_CURSORS lớn hơn số đối tượng SimpleJDBCCall thì sẽ không có phức tạp.

+5

Tôi hy vọng bạn báo cáo điều này nếu bạn coi đó là lỗi :) –

1

Tôi có thể hứa với bạn rằng đó không phải là Mùa xuân. Tôi đã làm việc trên một ứng dụng Spring 1.x đã phát hành vào năm 2005 và không bị rò rỉ kết nối kể từ đó. (WebLogic 9., JDK 5). Bạn không đóng tài nguyên của mình đúng cách.

Bạn có đang sử dụng hồ bơi kết nối không? Bạn đang triển khai máy chủ ứng dụng nào? Phiên bản nào của Spring? Oracle? Java? Chi tiết, xin vui lòng.

-3

Các giải pháp không phải là trong mùa xuân, nhưng trong Oracle: bạn cần phải thiết lập các thông số OPEN_CURSORS khởi đối với một số giá trị cao hơn so với mặc định 50.

Oracle - ít nhất là-của 8I, có lẽ nó đã thay đổi - - sẽ loại bỏ các đối tượng JDBC PreparedStatement trừ khi bạn để chúng mở. Điều này là tốn kém, và hầu hết mọi người cuối cùng duy trì một hồ bơi cố định của báo cáo mở được gửi lại.

(tham gia một cái nhìn lướt qua các tài liệu 10i, họ ghi rõ rằng người lái xe OCI sẽ cache PreparedStatements, vì vậy tôi giả định rằng người lái xe có nguồn gốc vẫn tái tạo chúng mỗi lần)

+2

Đây là một rò rỉ tài nguyên, giải pháp để rò rỉ tài nguyên là dừng rò rỉ, không thêm nhiều nước. –

+1

@Andrew - cảm ơn bạn đã bình luận cùng với lời bình luận của bạn. Tuy nhiên, đã làm việc với Oracle từ đầu những năm 1990, tôi đứng trước câu trả lời của tôi. Ra khỏi hộp, cấu hình của nó không phù hợp cho một ứng dụng phức tạp. Hơn nữa, OP đang sử dụng Spring, rất tốt trong việc tự dọn dẹp. Nó vẫn có thể là OP đã viết một tài nguyên bị rò rỉ ở đâu đó, nhưng ít có khả năng hơn nếu anh ta/cô ấy đã làm quản lý kết nối rõ ràng. – kdgregory

+0

Đọc lại tất cả các bài đăng, tôi thấy rằng OP đã đăng câu trả lời được chấp nhận sau hai tháng kể từ khi tôi trả lời, cho biết rằng thực tế nó đã bị rò rỉ tài nguyên với Spring. Tuy nhiên, do sự rò rỉ được cho là Spring cố gắng lưu trữ siêu dữ liệu, tôi sẽ tham chiếu đến đoạn thứ hai của tôi, và vẫn giữ nguyên câu trả lời này. – kdgregory

-2

Oracle OPEN_CURSORS là ổn chính . Chúng tôi có một ứng dụng 24x7 nhỏ chạy với Oracle XE chỉ với một vài con trỏ rõ ràng đang mở. Chúng tôi đã gặp lỗi con trỏ mở tối đa liên tục cho đến khi chúng tôi đặt giá trị khởi tạo OPEN_CURSORS thành> 300

+4

Đây là một rò rỉ tài nguyên, giải pháp cho một rò rỉ tài nguyên là để ngăn chặn rò rỉ, không thêm nhiều nước hơn. –

2

Chỉ cần cẩn thận đặt OPEN_CURSORS thành giá trị cao hơn và cao hơn vì có chi phí đầu vào và chỉ có thể hỗ trợ băng thông trên sự cố/lỗi thực tế ma cua ban.

Tôi không có kinh nghiệm với Spring về việc này nhưng đã làm việc trên một ứng dụng mà chúng tôi gặp nhiều sự cố với lỗi ORA-01000 và liên tục điều chỉnh OPEN_CURSORS vừa làm cho vấn đề biến mất trong một thời gian ...

3

Vâng, tôi gặp vấn đề này khi tôi đọc BLOB. Nguyên nhân chính là tôi cũng đang cập nhật bảng và mệnh đề Statement contains update không được đóng tự động. Nhồi mắt khó chịu ăn tất cả các con trỏ miễn phí. Sau khi cuộc gọi rõ ràng của statement.close() lỗi sẽ biến mất.

Đạo đức - luôn đóng mọi thứ, không dựa vào đóng tự động sau khi xử lý Tuyên bố.