在C#中强制关闭Oracle连接

8
我有一个报告窗口,它显示了从可能长时间运行的Oracle存储过程返回的结果。我的问题是当用户关闭窗口时,连接到Oracle仍然保持打开状态,潜在的长时间运行报告不会被取消。
唯一关闭打开连接的方法是DBA手动杀死它们或用户退出整个应用程序。
我尝试从不同的线程调用连接上的Close,但这似乎不断阻塞。我还尝试回滚事务,但这也存在相同的问题。
我担心唯一的解决方案将是在不同的进程(或者也许是应用程序域)中运行查询。
很可能我正在忽略一些显而易见的东西,非常感谢任何帮助。
请注意,这个问题不是关于将我的连接包装在using语句中。它是关于如何强制执行查询的Oracle连接关闭。
  • Start a thread running a query
  • Stash the connection object somewhere
  • Call close on the connection object

    public void Go()
    {
        OracleConnection connection;
        var queryThread = new Thread(
            () =>
                {
                    using (connection = OpenOracleConnection())
                    {
                        // execute stored proc that takes 45 mins
                        // raise an event with the data set we load
                    }
                });
    
        Thread.Sleep(3000); // give it time to be useless
    
        var closeThread = new Thread(
            () =>
                {
                    connection.Close();
                });
        closeThread.Start();
    }
    
问题在于这并没有关闭连接,而是调用connection.Close()会阻塞等待过程执行。

你使用的是哪个 ADO.NET Oracle 提供程序?(Microsoft 提供的那个不支持异步处理,所以如果是那个,你可能需要编写代码在另一个连接中连接并终止有问题的进程)。 - driis
这是随11.2.0附带的Oracle.DataAccess提供程序。 - jonnii
1
不是一个良好的问题。显然,您首先必须中止查询。在您解释如何引发这场灾难之前,您将无法得到答案,“报告窗口”是没有意义的。请发布代码。 - Hans Passant
感谢有用的反馈。虽然发布我的代码可能会很有用,但看到它的人会感到盲目。我从不同的线程运行Oracle过程是附带的,但我会尝试演示我的代码。 - jonnii
@Hans Passant,显然我必须中止查询。我该如何显然地中止查询? - jonnii
3个回答

3
嗯,我在API中没有看到任何取消/终止正在进行的查询的选项。从技术上讲,通过使用具有完全特权的第二个会话,应该可以识别要终止的会话并在该会话上发出kill session命令。我希望您的原始会话能够以某种异常退出,但我从未尝试过。
这里解释了如何终止会话。
这里回答了如何获取会话ID。您可以在启动长时间运行的查询之前找到它,然后从第二个连接轻松地终止该会话。
如果成功,请告诉我们 ;)

好主意,我会和数据库管理员商量一下,看看他们是否同意。我认为这可能意味着调用凭据具有更改系统的能力,这可能行不通。 - jonnii
你可以使用不同的用户来终止会话,不一定要使用相同的帐户... - flq
2
我已经快速制作出了这个并且它运行得很好,它指引了我正确的方向。我执行 select sid, serial# from v$session where audsid = sys_context('userenv','sessionid'),然后如果用户需要中止查询,就会跟着执行 alter system kill session(sid,session) immediate - jonnii
我在0.1%的情况下遇到ORA-00028错误。我正在IIS上运行数千个查询,每天有几次会出现“ORA-00028:您的会话已被终止”的情况。 - Toolkit

1

查看是谁/什么在阻塞谁:

select s1.username || '@' || s1.machine
   || ' ( SID=' || s1.sid || ' )  is blocking '
   || s2.username || '@' || s2.machine || ' ( SID=' || s2.sid || ' ) ' AS status
   from v$lock l1, v$session s1, v$lock l2, v$session s2
   where s1.sid=l1.sid and s2.sid=l2.sid
   and l1.BLOCK=1 and l2.request > 0
   and l1.id1 = l2.id1
   and l2.id2 = l2.id2;

0
与.NET中的任何提供程序一样,您都可以调用Dispose
using(var conn = /* your connection */) {
    // do your stuff

    conn.Close();
} // this will automatically call .Dispose()

这就是你需要做的全部。


当打开连接并当前正在执行查询的线程因阻塞45分钟时,我该如何调用close或dispose呢? - jonnii
我必须承认,我对Oracle数据库的经验有限,但我可以告诉你,查询被阻塞45分钟并不正常。如果您发布了如何打开连接的信息,这将有所帮助,您应该能够关闭连接,您无法关闭连接意味着是您的代码问题。 - Security Hound
并非所有的查询都需要45分钟,对于大多数查询,它们只需要几秒钟就能执行完毕,但这需要用户提供参数来缩小结果集,不幸的是,他们并不总是提供正确的参数。 - jonnii
哦,为了明确起见,如果您在TOAD中手动运行相同的查询,也需要45分钟,这进一步表明它与现有代码无关。 - jonnii

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接