診斷查詢
以下 SQL 查詢有助于診斷 ORA-01000 問題。要執行這些查詢,需要以管理員身份登錄數據庫,或獲得數據庫管理員從那些 v$ 視圖中進行選擇的授權。
1. 檢查數據庫中的 OPEN_CURSORS 參數值。
Oracle 使用 init.ora 中的初始化參數 OPEN_CURSORS 指定一個會話一次最多可以擁有的游標數。缺省值為 50。遺憾的是,此缺省值通常對 WebLogic Server 這樣的系統來說過小。要獲得數據庫中 OPEN_CURSORS 參數的值,可以使用以下查詢: |
SQL> show parameter open_cursors;
NAME TYPE VALUE
------------------------------------ ----------- ---------------
open_cursors integer 1000
|
重要的是將 OPEN_CURSORS 的值設置得足夠大,以避免應用程序用盡所有打開的游標。應用程序不同,該值也不同。即便會話打開的游標數未達 OPEN_CURSORS 指定的數量(即設置的值高于實際需要的值),也不會增加系統開銷。
2. 獲取打開的游標數。
下面的查詢按降序顯示用戶“SCOTT”為每個會話打開的游標數。 |
SQL> select o.sid, osuser, machine, count(*) num_curs
2 from v$open_cursor o, v$session s
3 where user_name = 'SCOTT' and o.sid=s.sid
4 group by o.sid, osuser, machine
5 order by num_curs desc;
SID OSUSER MACHINE NUM_CURS
-----------------------------------------------------
217 m1 1000
96 m2 10
411 m3 10
50 test 9 |
在 WebLogic Server 中使用連接池時,此查詢中的 user_name 應為用于創建連接池的 user_name(假定是從連接池得到連接)。該查詢結果還給出了計算機名稱。請在查詢結果中找出打開游標數量大的 SID 和運行 WebLogic Server 的計算機的名稱。
請注意,v$open_cursor 可以跟蹤會話中 PARSED 和 NOT CLOSED 的動態游標(使用 dbms_sql.open_cursor() 打開的游標)。它不會跟蹤未經分析(但已打開)的動態游標。在應用程序中使用動態游標并不常見。本模式的前提是未使用動態游標。
3. 獲取為游標執行的 SQL。使用在以上查詢結果中找到的 SID 運行下面的查詢: |
SQL> select q.sql_text
2 from v$open_cursor o, v$sql q
3 where q.hash_value=o.hash_value and o.sid = 217;
SQL_TEXT
------------------------------------------------------------------------------------------------------------------------
select * from empdemo where empid='212'
select * from empdemo where empid='321'
select * from empdemo where empid='947'
select * from empdemo where empid='527'
...
|
結果將顯示正在連接上執行的查詢。它提供了一個入手點,讓您可以反向跟蹤到打開游標的來源。返回頁首
常見成因及解決辦法
下面是查找問題成因及可能的解決辦法的步驟。
代碼慣例
此問題的最常見成因是未正常關閉 JDBC 對象。使用診斷查詢中第三個查詢的結果在應用程序代碼中反向跟蹤,確保將所有 JDBC 對象都正常關閉。BEA 建議在 finally 塊中顯式關閉 Connection、Statement 和 ResultSet 等 JDBC 對象,以確保無論是在正常還是異常情況下都將所有 JDBC 對象關閉。下面是一個常規示例: |
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = getConnection(); //Method getConnection will return a JDBC Connection
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from empdemo");
// do work
} catch (Exception e) {
// handle any exceptions
} finally {
try {
if(rs != null)
rs.close();
} catch (SQLException rse) {}
try {
if(stmt != null)
stmt.close();
} catch (SQLException sse) {}
try {
if(conn != null)
conn.close();
} catch (SQLException cse) {}
}
|
請避免采用任何放棄 JDBC 對象的代碼慣例。下面的代碼慣例在每個循環迭代中都獲得一個新的 Connection、Statement 和 ResultSet,但它沒有關閉每個迭代的 JDBC 對象。因此,它會導致 JDBC 對象泄漏。 |
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
String[] queries = new String[10];
//Define queries
try {
for(int i = 0; i < 10; i++) {
conn = getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery(queries[i]);
// do work
}
} catch (Exception e) {
// handle any exceptions
} finally {
try {
if(rs != null)
rs.close();
} catch (SQLException rse) {}
try {
if(stmt != null)
stmt.close();
} catch (SQLException sse) {}
try {
if(conn != null)
conn.close();
} catch (SQLException cse) {}
}
|
盡管根據 JDBC 規范的規定,關閉 Connection 時正常情況下也會將 Statement 和 ResultSet 關閉,但好的做法是:如果在一個 Connection 對象上創建了多個 Statement,則在使用完 Statement 和 ResultSet 后立即顯式將它們關閉。如果未立即顯式關閉 Statement 和 ResultSet,游標可能會積聚并在關閉 Connection 前超過數據庫允許的最大數量。例如,在以下代碼片斷中,正常情況下通過 finally 塊關閉 Connection 時,也會將 ResultSet 和 Statement 關閉。不過,此代碼片斷在一個連接上創建了多個 Statement 和 ResultSet。因此在循環完成前,可能已發生“超出最多允許打開的游標數”問題。 |
Connection conn = null;
try{
conn = getConnection();
for(int i = 0; i < NUM_STMT; i++) {
Statement stmt = null;
ResultSet rs = null;
stmt = conn.createStatement();
rs = stmt.executeQuery(/*some query*/);
//do work
}
} catch(SQLException e) {
// handle any exceptions
} finally {
try{
if(conn != null)
conn.close();
} catch(SQLException ignor) {}
}
|
返回頁首
語句緩存
為提高性能,WebLogic Server 提供了一種功能,讓您可以在使用連接池時將預處理語句和可調用語句載入緩存。當 WebLogic Server 將預處理語句或可調用語句載入緩存時,在許多情況下,DBMS 將為每個打開的語句都保留游標。因此,語句緩存可能是“超出最多允許打開的游標數”問題的成因。“語句緩存大小”屬性決定在每個連接池實例中為每個連接緩存的預處理和可調用語句的總數。如果緩存的語句過多,可能會導致超過數據庫服務器上打開游標數的上限。
請注意,各版本 WebLogic Server 的缺省語句緩存大小是有差異的。示例:
要確定“超出最多允許打開的游標數”問題是否與語句緩存有關,可以通過將語句緩存大小設置為 0 將此功能關閉或減少緩存大小,再確認是否仍會出現錯誤。如果在減少緩存大小后問題沒有發生,則說明連接池原有的語句緩存過大或 DBMS 中打開游標數的上限過低。可能需要考慮調整其中的一個值。如果發現連接上打開的游標數持續增加,但在將語句緩存大小設置為 0 后沒有出現這種現象,則可能說明存在游標泄漏問題。這可能是由使用的 JDBC 驅動程序所致,也可能是 WebLogic Server 本身的一個錯誤。請嘗試使用其它 JDBC 驅動程序。如果使用其它 JDBC 驅動程序后仍發生同樣的問題,請將此問題報告給 BEA,這樣支持工程師可以對問題做進一步探查,以確定該問題是否為 WebLogic Server 自身的一個錯誤。
返回頁首
數據庫驅動程序
“超出最多允許打開的游標數”問題的另一個可能成因是 JDBC 驅動程序有問題。為分清問題是驅動程序問題還是 WebLogic 連接池問題,如果有可重現的測試案例,可以嘗試執行以下步驟。
1. 直接從驅動程序獲取連接。
在測試案例中,繞過 WebLogic 連接池直接從驅動程序獲取 JDBC 連接。但請不要關閉連接,只需讓它們以數組或某種其它結構形式保持打開狀態,然后確認游標泄漏是否仍然存在。不關閉連接是因為要模擬使用連接池時的行為。使用連接池時,connection.close() 并未真正地關閉物理連接,而是將連接返回到池中。
2. 嘗試使用其它 JDBC 驅動程序。
可以嘗試使用其它供應商的 JDBC 驅動程序或升級版的驅動程序,然后確認問題是否仍然存在。可以使用元數據來驗證所使用的驅動程序是否正確。示例代碼與下面的類似: |
Connection conn = getConnection();
DatabaseMetaData dmd = conn.getMetaData();
System.out.println("JDBC Driver Name is " + dmd.getDriverName());
System.out.println("JDBC Driver Version is " + dmd.getDriverVersion()); |
posted on 2008-01-22 13:20
七匹狼 閱讀(1180)
評論(1) 編輯 收藏 所屬分類:
oracle