결과 세트를 닫은 후 Oracle이 커서를 제거하지 않음
참고: 단일 연결을 재사용합니다.
************************************************
public Connection connection() {
try {
if ((connection == null) || (connection.isClosed()))
{
if (connection!=null)
log.severe("Connection was closed !");
connection = DriverManager.getConnection(jdbcURL, username, password);
}
} catch (SQLException e) {
log.severe("can't connect: " + e.getMessage());
}
return connection;
}
**************************************************
public IngisObject[] select(String query, String idColumnName, String[] columns) {
Connection con = connection();
Vector<IngisObject> objects = new Vector<IngisObject>();
try {
Statement stmt = con.createStatement();
String sql = query;
ResultSet rs =stmt.executeQuery(sql);//oracle increases cursors count here
while(rs.next()) {
IngisObject o = new IngisObject("New Result");
o.setIdColumnName(idColumnName);
o.setDatabase(this);
for(String column: columns)
o.attrs().put(column, rs.getObject(column));
objects.add(o);
}
rs.close();// oracle don't decrease cursor count here, while it's expected
stmt.close();
}
catch (SQLException ex) {
System.out.println(query);
ex.printStackTrace();
}
파라미터 init.ora는open_cursors
세션이 한 번에 가질 수 있는 열려 있는 커서의 최대 수를 정의합니다.기본값은 50입니다.애플리케이션이 이 값을 초과하면 "ORA-01000: 최대 열린 커서 초과" 오류가 발생합니다.
따라서 JDBC 리소스가 더 이상 필요하지 않을 때, 특히 java.sql을 닫아야 합니다.결과 집합 및 java.sql.진술.응용프로그램이 닫히지 않으면 응용프로그램에서 리소스가 누출됩니다.
Connection 개체를 재사용하는 경우에는 열린 Oracle 커서가 연결이 존재하고 트랜잭션이 종료되지 않은 한 열려 있고 사용 중이라는 사실을 알고 있어야 합니다.애플리케이션이 커밋되면 열린 커서가 해제됩니다.
따라서 응용프로그램 설계자는 가장 복잡한 트랜잭션에 필요한 열린 커서의 대략적인 추정치를 알아야 합니다.
이 문제는 오라클의 내부 매개 변수 뷰(v$open_cursor, v$ssstat 등)가 열려 있는 커서와 열려 있는 커서 간의 차이를 표시할 수 없다는 데 있습니다. 열려 있는 커서는 여전히 닫히지 않은 ResultSet 또는 Stat에 의해 차단됩니다.마지막 블록에서 모든 문 및 결과 집합 개체를 닫으면 응용 프로그램이 완벽하게 정상입니다.
init.ora 파라미터를 조정하면 다음과 같이 작동합니다(애플리케이션에는 최대 800개의 커서가 필요합니다).
ALTER SYSTEM SET open_cursors = 800 SCOPE=BOTH;
올바른 방법은 모든 리소스를 자체 시도/캐치 블록의 마지막 블록에서 닫는 것입니다.저는 주로 다음과 같은 정적 유틸리티 클래스를 사용합니다.
public class DatabaseUtils
{
public static void close(Connection connection)
{
try
{
if (connection != null)
{
connection.close();
}
}
catch (SQLException e)
{
// log exception here.
}
}
// similar methods for ResultSet and Statement
}
그래서 나는 당신의 코드를 다음과 같이 쓸 것입니다.
public IngisObject[] select(String query, String idColumnName, String[] columns) {
Vector<IngisObject> objects = new Vector<IngisObject>();
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try
{
connection = connection();
stmt = con.createStatement();
// This is a SQL injection attack waiting to happen; I'd recommend PreparedStatemen
String sql = query;
rs =stmt.executeQuery(sql);//oracle increases cursors count here
while(rs.next())
{
IngisObject o = new IngisObject("New Result");
o.setIdColumnName(idColumnName);
o.setDatabase(this);
for(String column: columns) o.attrs().put(column, rs.getObject(column));
objects.add(o);
}
}
catch (SQLException ex)
{
System.out.println(query);
ex.printStackTrace();
}
finally
{
DatabaseUtils.close(rs);
DatabaseUtils.close(stmt);
DatabaseUtils.close(con);
}
일반적으로 결과 집합 및 문에 대한 닫기 문을 다음에 추가합니다.finally
예외가 발생한 경우(여기서 문제가 발생할 수 있음)에도 이들이 호출되도록 합니다.현재 코드에서 SQL 예외가 발생하면 두 개의 닫기( ) 메서드 호출이 발생하지 않고 커서가 열린 상태로 유지됩니다.
또한 열려 있는 커서의 수를 확인하기 위해 Oracle에서 어떤 쿼리를 사용하고 있습니까?
코드가 커서를 닫아야 합니다.그렇지 않으면 메서드를 호출하는 것과 커서 수가 1만큼 증가하는 1대 1의 상관 관계를 볼 수 있습니다.커서 수가 증가하는 예기치 않은 프로세스가 없는지 확인합니다.
권한이 있는 경우 데이터베이스에 대해 이 쿼리를 실행하여 열려 있는 커서 수를 나란히 표시하여 커서를 증가시키는 것이 다른 프로세스일 수 있으며, 이 프로세스가 커서를 증가시키는 것이 아닌지 확인할 수 있습니다.커서가 10개 이상 열려 있는 경우 이 값을 올려 노이즈를 필터링하거나 사용자 이름 또는 OS 사용자별로 범위를 좁힐 수 있습니다.
select oc.sid,
count(*) numCur,
s.username username,
s.osuser osuser,
oc.sql_text,
s.program
from v$open_cursor oc,
v$session s
where s.sid = oc.sid
group by oc.sid,
oc.sql_text,
s.username,
s.osuser,
s.program
having count(*) > 10
order by oc.sid;
여러 SID가 동일한 쿼리 문자열을 사용하여 위에서 공격자를 잘 드러내지 않는 경우 도움이 될 수 있는 다른 쿼리:
select oc.sql_text, count(*)
from v$open_cursor oc
group by oc.sql_text
having count(*) > 10
order by count(*) desc;
방금 같은 문제가 발생하여 연결을 닫지 않는 경우(나중에 다시 사용할 수 있으므로) 적어도 connection.rollback() 또는 connection.commit()을 수행해야 결과 집합 및 문을 닫을 때 열린 커서를 함께 해제할 수 있습니다.
언급URL : https://stackoverflow.com/questions/2560350/oracle-doesnt-remove-cursors-after-closing-result-set
'programing' 카테고리의 다른 글
인라인 변수가 있는 다중 줄 파이썬 문자열을 만들려면 어떻게 해야 합니까? (0) | 2023.07.09 |
---|---|
Python/SciPy를 위한 피크 찾기 알고리즘 (0) | 2023.07.09 |
앱이 실행될 때 Firebase에서 상태 업데이트를 기록하지 않도록 하는 방법 (0) | 2023.07.09 |
따옴표 없이 Excel 파일을 .txt 형식으로 저장 (0) | 2023.07.09 |
각도 6 관측 가능 항목에 항목 추가 (0) | 2023.07.09 |