2009-11-09 36 views
4

有时,当我在第三方专有JDBC驱动程序上调用connect()时,它永远不会返回,并且堆栈跟踪显示卡住等待套接字读取(通常)。有没有一种通用的方法来从另一个线程强制取消这个操作?这是一个阻塞的I/O调用,所以Thread.interrupt()将不起作用,并且我无法直接关闭套接字,因为我无法访问它,因为它是在专用代码中创建的。中断/取消卡住的connect()调用

我在寻找通用解决方案,因为我有一个异构的数据库环境(Oracle,MySQL,Sybase等)。但司机的具体建议也是受欢迎的。谢谢,

回答

2

没有标准的JDBC接口来设置连接或读超时,所以如果JDBC驱动程序完全支持超时,那么您必然会使用专有扩展。对于Oracle JDBC瘦驱动程序,您可以设置系统属性“oracle.net.CONNECT_TIMEOUT”或者“oracle.jdbc.ReadTimeout”,或者将一个Properties实例传递给DriverManager.getConnection并设置这些属性。虽然没有特别详细记录,但Oracle特定属性列在API documentation中。

对于其他JDBC驱动程序,文档应包含相关参考。

1

至少有一个JDBC驱动程序(不是您列出的那个驱动程序)将干净地关闭连接,如果此连接尝试运行的线程中断。我不知道这是否会适用于所有司机。

2

啊......使用封闭源代码库的乐趣...

如果interrupt()不工作,你不能设置一些超时,那么我认为是没有安全的方式来做到这一点。打电话Thread.kill()可能做这项工作,但该方法已被弃用,因为它是非常不安全的。而这种情况下Thread.kill()的不安全性可能会回来并咬你。

我建议你简单地编写你的应用程序来放弃卡住的线程。假设您的应用程序不会反复尝试连接到数据库,卡住的线程并不是很大的开销。

或者使用更好的JDBC驱动程序。 (并且在出门的时候,向供应商抱怨他们的驱动程序太不灵活了,有人可能会听你的...)

+0

这是一个选项,我已经打了,但它实际上相当于同样的事情,放弃线程,因为使用Thread.stop ()不影响阻塞I/O操作。 – Dan 2009-11-10 16:01:54

0

这是Java的问题,而不是JDBC驱动程序。在某些情况下,套接字连接调用会忽略超时参数,并可能需要几分钟才能返回。当防火墙阻止端口时,这发生在我们身上。它发生在所有的TCP连接(HTTP,RMI)上。

我找到的唯一解决办法就是打开在不同的线程这样的连接,

private static final ExecutorService THREADPOOL 
     = Executors.newCachedThreadPool(); 

    private static <T> T call(Callable<T> c, long timeout, TimeUnit timeUnit) 
     throws InterruptedException, ExecutionException, TimeoutException 
    { 
     FutureTask<T> t = new FutureTask<T>(c); 
     THREADPOOL.execute(t); 
     return t.get(timeout, timeUnit); 
    } 

    try { 
     Data data = call(new Callable<Data>() { 
      public Data call() throws Exception 
      { 
       // Open connection, get data here 
       return data; 
      }, 2, TimeUnit.SECONDS); 
    } catch (TimeoutException e) { 
     System.err.println("Data call timed-out"); 
    } 
+0

我会尝试。我不能放弃主线程,因为它位于servlet容器的托管池中,但这应该起作用。 – Dan 2009-11-10 16:04:41