How do I forcefully close a connection from a connection pool when it's taking too much time to close?

我怕爱的太早我们不能终老 提交于 2019-12-21 21:51:07

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!