问题
There are times closing connections takes a lot of time, like more than 10 minutes upto 1 hour, or worse, even for indefinite time, depending on how heavy or slow the query was.
In a situation where the client cancels the query because it has been taking too much time, I would want to free up the underlying connection used as soon as possible.
I tried cancelling the PreparedStatement, closing it, then closing the resultset, and then finally closing the connection. Cancelling took almost instantly. Closing the PreparedStatement and ResultSet took too much time that I had to wrap it in a Callable with timeout to skip that process in due time and proceed with closing the connection itself. I haven't got any much luck on what else to try out.
How do I deal with this? I can't simply let the connections unclosed and I can't let the users wait for 10 minutes before they can make another similar query.
Also, what's causing the closure of connection to take too much time? Is there anything else I could do? Do you think Oracle query hints would help?
I'm using Oracle JDBC via thin type of driver by the way.
UPDATE:
Apparently, it's possible to close the connection forcefully by configuring TimeToLive property in the connectionCacheProperties which closes the connection for a specific amount of time. However, what I need is on as-needed basis. This is worth mentioning because this proves that it is possible to forcefully close it as the Connection Pool just did. In fact, I even got the following message on my logs.
ORA-01013: user requested cancel..
回答1:
Main function:
String g_sid = "";
Thread 1:
String sql = ...;
Connection conn = ...your connection func...;
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery( "SELECT sid from v$mystat");
if (rset.next()) g_sid = rset.getString("sid");
rset.close();
// now to the actual long-running SQL
ResultSet rset = stmt.executeQuery( sql );
//
stmt.close();
Thread 2:
String serialN = "";
Connection conn = ...your admin connection func...
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery( "SELECT serial# serialN from v$session where sid=" + g_sid );
if (rset.next()) {
serialN = rset.getString("serialN");
stmt.execute("alter system kill session '" + g_sid + "," + serialN + "'");
}
stmt.close();
// probably keep the admin connection open for further maintenance
//
回答2:
This is what we use at my POW instead of "grant alter system to $UID" as a SYS-owned procedure (simplified working version):
CREATE OR REPLACE procedure SYS.kill_session(in_sid varchar2)
as
l_serial number;
l_runsql varchar2(1000) := 'alter system kill session ''$1,$2'' immediate';
begin
begin
select serial# into l_serial from v$session where username =
(
SELECT USER FROM DUAL
) and sid=in_sid and rownum<=1;
exception when no_data_found then
raise_application_error( -20001, 'Kill candidate not found');
end;
l_runsql := replace( l_runsql, '$1', in_sid);
l_runsql := replace( l_runsql, '$2', l_serial);
execute immediate l_runsql;
end;
/
This way you can only kill your own sessions.
来源:https://stackoverflow.com/questions/44383579/how-do-i-forcefully-close-a-connection-from-a-connection-pool-when-its-taking-t